How can I make Jekyll use a layout without specifying it? - ruby

In order to keep some of my Jekyll sites simple, I'm always using the same layout. That is to say, I'm always writing something like. . .
---
layout: default
title: Here's my Title
---
. . . as the YAML Front Matter at the top of my pages.
What I'd rather write, however is only. . .
---
title: Here's my Title
---
. . . and have Jekyll assume that it should use a certain layout, as if I had explicitly written "layout: default" (or whatever), as above.
I don't see a way to specify this behavior in _config.yml. Maybe I could write a Jekyll plugin that would allow this. . . any ideas?

This can be done using Frontmatter defaults:
defaults:
-
scope:
path: "" # empty string for all files
values:
layout: "default"
This setting is available since Jekyll Version 2.0.0.

Shorter and with no monkey-patching:
# _plugins/implicit_layout.rb
module ImplicitLayout
def read_yaml(*args)
super
self.data['layout'] ||= 'post'
end
end
Jekyll::Post.send(:include, ImplicitLayout)
Caveat: GH Pages won't run your plugins.

Here's a Jekyll plugin you can drop in as _plugins/implicit-layout.rb, for example:
# By specifying an implicit layout here, you do not need to
# write, for example "layout: default" at the top of each of
# your posts and pages (i.e. in the "YAML Front Matter")
#
# Please note that you should only use this plugin if you
# plan to use the same layout for all your posts and pages.
# To use the plugin, just drop this file in _plugins, calling it
# _plugins/implicit-layout.rb, for example
IMPLICIT_LAYOUT = 'default'
module Jekyll
module Convertible
def read_yaml(base, name)
self.content = File.read(File.join(base, name))
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
self.content = $POSTMATCH
begin
self.data = YAML.load($1)
self.data["layout"] = IMPLICIT_LAYOUT
rescue => e
puts "YAML Exception reading #{name}: #{e.message}"
end
end
self.data ||= {}
end
end
end
From hanging out on #jekyll on freenode, I'm given to understand this is a monkey patch.
As Alan W. Smith commented, being able to put "layout: default" in _config.yml would be a nice improvement to this plugin.
Ideally (from my perspective), this functionality could be incorporated in Jekyll itself so a plugin wouldn't be necessary.

By default, you can't do this. Jekyll needs the YAML to specify layout so it knows where to drop it in at.

Related

How do you use cucumber with zeus?

When I start up zeus, it does not offer zeus cucumber as one of the possible commands. Others seem to get this by default; At least I have seen a couple zeus write-ups that show the output from zeus start including zeus cucumber, and they don't say anything about that having been special or required extra configuration.
I don't really even know where to start to troubleshoot this; I have googled and searched here for "use cucumber with zeus." I get no setup discussions. The only results I get are from people who seem to take for granted that it should be there, and are investigating problems with it not functioning correctly.
You should use this custom plan file from Zeus. Save it as custom_plan.rb at the root of your application:
require 'zeus/rails'
# 1. Add the cucumber methods (below) to your custom plan (or take this file if
# you don't have an existing custom_plan).
#
# 2. Add the following line to the test_environment section of your zeus.json:
#
# "cucumber_environment": {"cucumber": []}
class CucumberPlan < Zeus::Rails
def cucumber_environment
::Rails.env = ENV['RAILS_ENV'] = 'test'
require 'cucumber/rspec/disable_option_parser'
require 'cucumber/cli/main'
#cucumber_runtime = Cucumber::Runtime.new
end
def cucumber(argv=ARGV)
cucumber_main = Cucumber::Cli::Main.new(argv.dup)
had_failures = cucumber_main.execute!(#cucumber_runtime)
exit_code = had_failures ? 1 : 0
exit exit_code
end
end
Zeus.plan = CucumberPlan.new

How to define a simple global variable in an rspec test that can be accesed by helper functions

I cant figure out how to use a simple global variable in an rspec test. It seems like such a trivial feature but after much goggleing I havent been able to find a solution.
I want a variable that can be accessed/changed throughout the main spec file and from functions in helper spec files.
Here is what I have so far:
require_relative 'spec_helper.rb'
require_relative 'helpers.rb'
let(:concept0) { '' }
describe 'ICE Testing' do
describe 'step1' do
it "Populates suggestions correctly" do
concept0 = "tg"
selectConcept() #in helper file. Sets concept0 to "First Concept"
puts concept0 #echos tg?? Should echo "First Concept"
end
end
.
#helpers.rb
def selectConcept
concept0 = "First Concept"
end
Can someone point out what I am missing or if using "let" is totally the wrong method?
Consider using a global before hook with an instance variable: http://www.rubydoc.info/github/rspec/rspec-core/RSpec/Core/Configuration
In your spec_helper.rb file:
RSpec.configure do |config|
config.before(:example) { #concept0 = 'value' }
end
Then #concept0 will be set in your examples (my_example_spec.rb):
RSpec.describe MyExample do
it { expect(#concept0).to eql('value') } # This code will pass
end
It turns out the easiest way is to use a $ sign to indicate a global variable.
See Preserve variable in cucumber?
This is an old thread, but i had this question today. I just needed to define a long string to stub out a command that is in multiple files as:
# in each spec file that needed it
let(:date_check) do
<<~PWSH.strip
# lots of powershell code
PWSH
end
# in any context in that file (or a shared context)
before(:each) do
stub_command(date_check).and_return(false)
end
Searched, Stack Overflow, etc, landed on this: Note the usage of the variable doesn't change at all! (Assumes all specs require 'spec_helper')
# in spec_helper.rb
def date_check
<<~PWSH.strip
# lots of powershell code
PWSH
end
# in any context in any spec file
before(:each) do
stub_command(date_check).and_return(false)
end
I suggest you define the variable in the helper file, where it can be used by other helper code, and can be accessed from your tests.
For my project, I wanted to keep all the setup stuff in spec_helper.rb, and use those settings, plus any custom variables and methods in the tests. The following, modified from the RSpec-core 3.10 docs, is not Rails-specific.
Create a new setting for RSpec.configure called my_variable, and give it a value, like this:
# spec/spec_helper.rb
RSpec.configure do |config|
config.add_setting :my_variable
config.my_variable = "Value of my_variable"
end
Access settings as a new read-only property in RSpec.configuration from your test:
# spec/my_spec.rb
RSpec.describe(MyModule) do
it "creates an instance of something" do
my_instance = MyModule::MyClass.new(RSpec.configuration.my_variable)
end
end

Get Jekyll Configuration Inside Plugin

I'd like to make changes to the Jekyll Only First Paragraph plugin to make the generation of a 'read more ' link a configurable option.
To do this I'd need to be able to access the Jekyll site config inside the plugin's AssetFilter. With the configuration available I can make the change. I don't know how to make the site configuration available to the plugin.
The code below demonstrates where I'd like site.config available:
require 'nokogiri'
module Jekyll
module AssetFilter
def only_first_p(post)
# site.config needs to be available here to modify the output based on the configuration
output = "<p>"
output << Nokogiri::HTML(post["content"]).at_css("p").inner_html
output << %{</p><a class="readmore" href="#{post["url"]}">Read more</a>}
output
end
end
end
Liquid::Template.register_filter(Jekyll::AssetFilter)
Can this be achieved?
Overview
You can access Jekyll config options in plugins with:
Jekyll.configuration({})['KEY_NAME']
If the config key contains nested levels, the format is:
Jekyll.configuration({})['KEY_LEVEL_1']['KEY_LEVEL_2']
Example
If a _config.yml contains:
testvar: new value
custom_root:
second_level: sub level data
A basic example that simply outputs those values would look like:
require 'nokogiri'
module Jekyll
module AssetFilter
def only_first_p(post)
#c_value = Jekyll.configuration({})['testvar']
#c_value_nested = Jekyll.configuration({})['custom_root']['second_level']
output = "<p>"
### Confirm you got the config values
output << "<br />"
output << "c_value: " + #c_value + "<br />"
output << "c_value_nested: " + #c_value_nested + "<br />"
output << "<br />"
###
output << Nokogiri::HTML(post["content"]).at_css("p").inner_html
output << %{</p><a class="readmore" href="#{post["url"]}">Read more</a>}
output
end
end
end
Liquid::Template.register_filter(Jekyll::AssetFilter)
Of course, you would want to put checks in that verify that the config key/values are defined before trying to use them. That's left as an exercise for the reader.
Another Possible Option
The "Liquid filters" section of the Jekyll Plugins Wiki Page contains the following:
In Jekyll you can access the site object through registers. As an example, you can access the global configuration (_config.yml) like this: #context.registers[:site].config['cdn'].
I haven't spent the time to get that to work, but it might be worth checking out as well.
Jekyll.configuration({})['KEY_NAME'] will break the --config command line option because it will always load the configurations from the _config.yml file. Another bad side effect is that it will read the _config.yml file again.
context.registers[:site].config['KEY_NAME'] is the correct answer because it will get the key from the configurations already loaded by Jekyll.
If you are working with Generators (which are also plugins), it is possible to get the configuration like this:
class MyPlugin < Jekyll::Generator
def generate(site)
puts site.config["max_posts"] # max_posts as defined in _config.yml
You'll get the site as an argument, and the .config is accessible as an hash.

How to add a page to RDoc?

Noob here trying to figure out the simple task of adding a page to my RDoc documentation. If I do rake doc:app and view a page, then there is a sidebar that says "Pages" with README_FOR_APP listed. All I want to do is create a page named "Cheatsheet" that will appear under "Pages." How do I create a documentation page and tell RDoc to include the new page?
IMO it's a bit convoluted. Here's the references I used:
http://rake.rubyforge.org/classes/Rake/RDocTask.html
How to Rename or Move Rails's README_FOR_APP
Nutshell version:
Take the "app" task from your rails library directory, for example I tested using:
~/.rvm/gems/ruby-1.9.2-p0#foo/gems/railties-3.0.9/lib/rails/tasks/documentation.rake
The part you need looks (approximately) like this:
namespace :doc do
def gem_path(gem_name)
path = $LOAD_PATH.grep(/#{gem_name}[\w.-]*\/lib$/).first
yield File.dirname(path) if path
end
RDocTaskWithoutDescriptions.new("app2") { |rdoc|
rdoc.rdoc_dir = 'doc/app'
rdoc.template = ENV['template'] if ENV['template']
rdoc.title = ENV['title'] || "Rails Application Documentation"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '--charset' << 'utf-8'
rdoc.rdoc_files.include('doc/*_FOR_APP') # Modified this line
rdoc.rdoc_files.include('app/**/*.rb')
rdoc.rdoc_files.include('lib/**/*.rb')
}
end
Put this in your app's lib/tasks directory in a .rake file, e.g., doc2.rake.
Update the task name if you want to keep the original, e.g., "app2".
Update the "doc/README_FOR_APP" string to a wider pattern, or add new file(s) to process.
Create doc/Cheatsheet_FOR_APP and the new rake doc:app2 task will pick it up.

ruby-inotify example?

I'm looking for a simple, concise example of using the inotify gem to detect a change to a directory.
It lacks examples.
There's an example in examples/watcher.rb.
That link is to aredridel's repo, since it looks like you linked to aredridel's docs, and aredridel is the one who wrote the example.
One of my projects I have used ruby-inotify for monitoring file creation under specific folder using following code
# frozen_string_literal: true
require 'rb-inotify'
# observe indicate folder, trigger event after
module ObserveFiles
def self.observe
watcher = INotify::Notifier.new
directory = CONFIG['xml_folder'] # folder that want to watch
watcher.watch(directory, :create) do |event|
# do your work where
# here, event.name is created file name
# event.absolute_name file absolute path
end
watcher.run
end
end
Use this code like
ObserveFiles.observe
Hope this will help someone.

Resources