Last modified date hook to collection - jekyll

I'm trying to apply this hook to a custom collection:
Hook
Jekyll::Hooks.register :docs, :pre_render do |post|
# get the current post last modified time
modification_time = File.mtime( post.path )
# inject modification_time in post's datas.
post.data['last-modified-date'] = modification_time
end
Collection
collections:
docs:
output: true
But right now the last-modified-date isn't being assigned.
I saw on this comment that using the collection name should work.
I'm trying to order them by date and list them, but right now the field is coming out empty. All my fields on doc where created before setting up the hook, so maybe I need to do something for it to work.
Any ideas?
When does the hook run? (specially for pre-existent files)
How should I set it up to work with a collection?

Try this, it is supposed to output some info in your console when you build or serve you jekyll site locally. This can help to debug.
_plugins/hook-docs-pre-render.rb
Jekyll::Hooks.register :docs, :pre_render do |post|
# debug
puts "Firing :docs, :pre_render from : " + File.basename(__FILE__) + " for : " + post.relative_path
# get the current post last modified time
modification_time = File.mtime( post.path )
# debug
puts "modification_time = " + modification_time.strftime('%A, %B %dth %Y at %l:%M%p')
# inject modification_time in post's datas.
post.data['last-modified-date'] = modification_time
end
Note that hooks are not working on github pages.

Related

Nokogiri Exclude HTML Class

I'm trying to scrape the names of all the people who commented on a post in our Facebook group. I downloaded the file locally and am able to scrape the names of the people who commented plus the people who replied to those comments. I only want the original comments, not the replies... it seems like I have to exclude the UFIReplyList class but my code is still pulling all the names. Any help would be greatly appreciated. Thanks!
require 'nokogiri'
require 'pry'
class Scraper
##all = []
def get_page
file = File.read('/Users/mark/Desktop/raffle.html')
doc = Nokogiri::HTML(file)
# binding.pry
doc.css(".UFICommentContent").each do |post|
# binding.pry
author = post.css(".UFICommentActorName").css(":not(.UFIReplyList)").text
##all << author
end
puts ##all
end
end
Scraper.new.get_page
Traverse ancestors for every .UFICommentActorName element, to reject those contained within a .UFIReplyList element.
#authors_nodes = doc.css(".UFICommentActorName").reject do |node|
# extract all ancestor class names;
# beware of random whitespace and multiple classes per node
class_names = node.ancestors.map{ |a| a.attributes['class'].value rescue nil }
class_names = class_names.compact.map{ |names| names.split(' ') }
class_names = class_names.flatten.map(&:strip)
# reject if .UFIReplyList found
class_names.include?('UFIReplyList')
end
#authors_nodes.map(&:text)

Passing the value from a ruby block to a resource in chef

I am writing a chef resource, which will generate a password, and I am calling that resource in a recipe with the list of inputs.
Following is my scenario: Once my resource got executed, a new set of passwords will be generated in a folder, and I want to retrieve that password which is newly generated. But I am unable to retrieve that password because the value I am trying to retrieve is executing at the convergence phase.
Simple code block to explain my scenario:
Chef::Log.info("Creating new keys")
create_password 'New Password is being generated' do
action :change_passwords
password_util_dir node[:password][:passwd_util_dir]
rgbu_chef node[:password][:rgbu_chef]
old_data_bags node[:password][:old_data_bags]
new_data_bags node[:password][:new_data_bags]
end
The code above will create new passwords in a folder.
Later, I am trying to take the passwords through a JSON Parser:
text =::File.read("#{new_password_dir}")
data_hash = JSON.parse(text)
new_wls_password = data_hash['rase_wlsadmin_pwd']
The #{new_password_dir} is the directory location of the newly created password.json file.
I am trying to use the value of "new_wls_password" in the another resource like below:
Chef::Log.info("Updating WLSADMIN Password")
passwd_backup 'Updating wlsadmin password' do
action :update_wlsadmin
osuser node[:password][:wls_config_user]
usergroup node[:password][:wls_install_group]
new_wls_password "#{new_wls_password}"
end
Here, the new password which I am trying to retrieve is empty, since the following three lines are executed in the first place:
text =::File.read("#{new_password_dir}")
data_hash = JSON.parse(text)
new_wls_password = data_hash['rase_wlsadmin_pwd']
So, by that time, the new passwords resource has not been run.
I tried many stack overflow suggestions, like:
putting those three lines in a ruby_block like this
ruby_block "new_password" do
block do
text =::File.read("#{new_password_dir}")
data_hash = JSON.parse(text)
node.set[:new_wls_password] = data_hash['rase_wlsadmin_pwd']
end
end
Then I tried fetching the value into the resource as below
Chef::Log.info("Updating WLSADMIN Password")
passwd_backup 'Updating wlsadmin password' do
action :update_wlsadmin
osuser node[:password][:wls_config_user]
usergroup node[:password][:wls_install_group]
new_wls_password "#{node[:new_wls_password]"
end
With the above approach still the value is empty
Trying the value with lazy and calling that value.
Passing the value from one ruby block to another ruby block, which I can do, but not with the resources.
Please, can you help?
EDIT #1 :
I need to pass the value from the resource to the template.
Something like this, after running the following resource:
Chef::Log.info("Creating new keys")
create_password 'New Password is being generated' do
action :change_passwords
password_util_dir node[:password][:passwd_util_dir]
rgbu_chef node[:password][:rgbu_chef]
old_data_bags node[:password][:old_data_bags]
new_data_bags node[:password][:new_data_bags]
end
A new set of passwords will be generated in a folder, like the /tmp/password.json file.
After the resource execution above I am writing a template like:
template "#{Chef::Config[:file_cache_path]}/domain.properties" do
source 'domain_properties.erb'
variables
({ :domain_name => "#{domain_name}",
:admin_url => "#{admin_url}",
:new_wls_password => "#{new_wls_password}" })
end
Here, how can I parse the newly created value of "new_wls_password" ?
You can use lazy attribute like below:-
Chef::Log.info("Updating WLSADMIN Password")
passwd_backup 'Updating wlsadmin password' do
action :update_wlsadmin
osuser node[:password][:wls_config_user]
usergroup node[:password][:wls_install_group]
new_wls_password lazy { JSON.parse(File.read("/tmp/password.json"))['rase_wlsadmin_pwd'] }
end
Template resource can be written as:-
template "#{Chef::Config[:file_cache_path]}/domain.properties" do
source 'domain_properties.erb'
variables (lazy{{ :domain_name => "#{domain_name}",
:admin_url => "#{admin_url}",
:new_wls_password => JSON.parse(File.read("/tmp/password.json"))['rase_wlsadmin_pwd'] }})
end
Output:-
* template[/tmp/kitchen/cache/domain.properties] action create
- create new file /tmp/kitchen/cache/domain.properties
- update content in file /tmp/kitchen/cache/domain.properties from none to fa22e0
--- /tmp/kitchen/cache/domain.properties 2017-01-12 03:30:13.002968715 +0000
+++ /tmp/kitchen/cache/.chef-domain20170112-11387-1ytkyk2.properties 2017-01-12 03:30:13.002968715 +0000
## -1 +1,4 ##
+domain_name= mmm
+admin_url= nnn
+new_wls_password= xH#3zIS9Q4Hc#B

Rails 2 hook to modify data before it is read/written to MySQL DB

I have a rails 2 application that I am trying to modify so that before an attribute is written to my MySql DB, it is encoded, and on read, it is decoded (not all attributes, just pre-determined ones).
I have looked at some gems, specifically attr-encrypted, but it doesn't do exactly what I want (I am also trying to avoid re-naming any of my existing table columns, which appears to be a requirement for attr-encrypted).
I have added a before_save filter to my model to do the attribute modification before it is saved to the DB, and I have overridden my attribute getter to do the decode. While this works, I want to do the decode lower in the stack (i.e. right after DB read) in order to have everything function correctly, without requiring system wide changes (it also simplifies the logic when deciding when to encode/decode).
So what it means is that I want to do the following:
1) On DB read, do the reverse, so that if i do a Model.last, the value for my attribute would be the decoded value (without having to explicitly call the attribute getter).
2) Override the find_by_* methods so that doing a search by my encoded attribute will encode the search term first, then do the db query using that value.
How would I go about doing that?
Update: this method unfortunately does not work in Rails 2. Custom serializers were probably added in Rails 3.
Original answer follows:
I think you can try to use a custom serializer as described in this blog post. This feature should be present even in Rails 2 (otherwise I guess these SO questions regarding it would not exist).
Sample serializer which encodes the attribute into Base64:
# app/models/model.rb
class Model < ActiveRecord::Base
serialize :my_attr, MyEncodingSerializer
end
# lib/my_encoding_serializer.rb
class MyEncodingSerializer
require "base64"
def self.load(value)
# called when loading the value from DB
value.present? ? Base64.decode64(value) : nil
end
def self.dump(value)
# called when storing the value into DB
value.present? ? Base64.encode64(value) : nil
end
end
Test in the rails console:
>> Model.create(my_attr: "my secret text")
D, [2016-03-14T07:17:26.493598 #14757] DEBUG -- : (0.1ms) BEGIN
D, [2016-03-14T07:17:26.494676 #14757] DEBUG -- : SQL (0.6ms) INSERT INTO `models` (`my_attr`) VALUES ('bXkgc2VjcmV0IHRleHQ=\n')
D, [2016-03-14T07:17:26.499356 #14757] DEBUG -- : (4.4ms) COMMIT
=> #<Model id: 4, my_attr: "my secret text">
You can see that the my_attr value gets automatically encoded before saving to the DB.
Loading from DB of course works transparently too:
>> Model.last
D, [2016-03-14T07:19:01.414567 #14757] DEBUG -- : Model Load (0.2ms) SELECT `models`.* FROM `models` ORDER BY `models`.`id` DESC LIMIT 1
=> #<Model id: 4, my_attr: "my secret text">
All finder helpers should work too, for example:
>> Model.find_by_my_attr("other text")
D, [2016-03-14T07:20:06.125670 #14757] DEBUG -- : Model Load (0.3ms) SELECT `models`.* FROM `models` WHERE `models`.`my_attr` = 'b3RoZXIgdGV4dA==\n' LIMIT 1
=> nil # nothing found here for wrong my_attr value
>> Model.find_by_my_attr("my secret text")
D, [2016-03-14T07:21:04.601898 #14757] DEBUG -- : Model Load (0.6ms) SELECT `models`.* FROM `models` WHERE `models`.`my_attr` = 'bXkgc2VjcmV0IHRleHQ=\n' LIMIT 1
=> #<Model id: 4, my_attr: "my secret text"> # FOUND!
It looks like rails 2 has the 'after_initialize' callback which should get you what you want (at a bit of a performance hit):
class Model < ActiveRecord::Base
after_initialize do |model|
# your decryption code here
end
end
http://guides.rubyonrails.org/v2.3.11/activerecord_validations_callbacks.html#after-initialize-and-after-find

Generator plugin doesn't render data

I am writing a jekyll plugin to render an alternative layout for my posts in category "portfolio". The files are generated in the partial folder but the data is not rendered. What am I doing wrong?
Generator:
module Jekyll
class PartialGenerator < Generator
def generate(site)
site.categories['portfolio'].each do |post|
site.pages << PartialPage.new(site, site.source, post)
end
end
end
class PartialPage < Page
def initialize(site, base, post)
#site = site
#base = base
#dir = 'partials'
#name = "#{post.id}.html".tr('/','')
self.process(name)
self.read_yaml(File.join(base, '_layouts'), "partial.html")
self.data['page'] = post
end
end
end
The partial.html layout includes <h1>{{ page.title }}</h1> and the generated output is <h1></h1>
I've tried puts(post.title) in the initialize method and it prints the correct titles on the console.
I found the solution myself now.
The data you put into self.data[]is available as property of page in the template/layout.
So self.data[‘test'] = "..." can be accessed through {{page.test}}.
Now my generator includes self.data['page'] = post and I access it in my partial.html as <h1>{{page.post.title}}</h1>.

How can I store a hash for the lifetime of a 'jekyll build'?

I am coding a custom Liquid tag as Jekyll plugin for which I need to preserve some values until the next invocation of the tag within the current run of the jekyll build command.
Is there some global location/namespace that I could use to store and retrieve values (preferably key-value pairs / a hash)?
You could add a module with class variables for storing the persistent values, then include the module in your tag class. You would need the proper accessors depending on the type of the variables and the assignments you might want to make. Here's a trivial example implementing a simple counter that keeps track of the number of times the tag was called in DataToKeep::my_val:
module DataToKeep
##my_val = 0
def my_val
##my_val
end
def my_val= val
##my_val = val
end
end
module Jekyll
class TagWithKeptData < Liquid::Tag
include DataToKeep
def render(context)
self.my_val = self.my_val + 1
return "<p>Times called: #{self.my_val}</p>"
end
end
end
Liquid::Template.register_tag('counter', Jekyll::TagWithKeptData)