Extending Faker in a gem, where do I put the YAML file? - ruby

I have a gem which uses Faker to help build mock data. I'd like to add a new class that generates a new category of stuff, using the same syntax Faker itself uses. The first half is easy, I simply define the class, and make sure my gem loads the file:
# lib/faker/restaurant.rb
module Faker
class Restaurant < Base
class << self
def name
parse('restaurant.name')
end
end
end
end
So far, so good. Now, to describe what values can come out of this, I create a YAML file:
faker:
en:
restaurant:
suffix: [Cafe,Restaurant]
name:
- "#{Name.first_name}'s #{suffix}"
So, the actual question: Where does this file go, and what name should it have? If this were a Rails application, it would be config/locales/faker.en.yml. In a gem, that doesn't appear to work - there isn't actually a 'config' directory, for one thing, but creating it for this purpose doesn't help, I get:
> Faker::Restaurant.name
I18n::MissingTranslationData: translation missing: en.faker.restaurant.name

Ok, figured it out. Special thanks to dax, whose comments prodded me in the right direction.
Faker uses the I18n gem for localization (which is why the YAML files live in a 'locales' directory). This means that I needed to add my custom YAML to the I18n load path. It doesn't matter exactly where the files are, as long as they're added to the load path. In my case, I put it at lib/faker/locales/en-US.yml, and added that entire directory to the load path, thus:
lib/my_gem.rb:
I18n.load_path += Dir[File.join(File.expand_path(File.dirname(__FILE__)), 'faker/locales', '*.yml')]
require "faker/restaurant"
Any .yml files I put in that directory should be loaded and available to Faker.
Side note: I also needed to change the YAML format slightly - it should be
en:
faker:
<stuff>
rather than with faker at the top level, as I had it.

Related

RuboCop Error - Define a global variable in Cucumber RUBY files

I need to define a global variable in my Cucumber env.rb file which can be accessed throughout the framework in all step methods. Currently i am defining as this in my env.rb file:
$global_var ||= false
And i need to access this var into the Before hook as well After hook and few step methods where i am re-initializing this. It is working perfectly as i want. But the problem is, rubocop doesn't like this and throwing error as "do not use global variable". How can i resolve this ???
FYI, I tried using singleton to define this var as accessor and not quite sure where i am missing.
Change the config file for rubocop. use the link:
Example to Change
Look for the passage starting with When we look in the .rubocop_todo.yml file we see something like this: and also Configure Rubocop to be your style guide
Link to List of Configuration Changes possible:
Link to List of Styles
change .rubocop.yml file:
Style To Change:
GlobalVars: Enabled: false
Example File : Example file - how it looks like
How to Configure Style: Style/Inheritance Guide

Sinatra: put some of my helpers in separate folder

I have a Sinatra app and I have some helpers and they have their folder (helpers) in which I have website_helpers.rb and so on. I want to move some of this helpers in their own folder inside the helpers folder: to have helpers/subhelpers, bacause the files I want to put in the subhelpers folder are different from the others and it makes sense to have a different folder for them.
I tried adding this to my config.ru
Dir.glob('./helpers/subhelpers/*.rb').each { |file| require file }
And then in the controller I have:
helpers MyHelperFromSubHelpers
but I get an error uninitialized constant (NameError).
Any ideas how to fix this so that to have a clear structure?
TBH, it sounds like you're overdoing it, there's always Rails if you want to go in for a more Java like every-namespace-must-be-a-directory layout. Aside from that, usually, helpers in separate files are placed in the Sinatra namespace - see http://www.sinatrarb.com/extensions.html#extending-the-request-context-with-sinatrahelpers
Personally, I put them in:
project-root/
lib/
sinatra/
name-of-extension.rb
Mainly because if the extension is really useful, I'll end up wanting to use it in another project, and this is the standard layout for a Sinatra gem, which makes it easy to extract it into one and with barely any change in the calling code.
Dir.glob will only return the file name and not the full path with each match, so you need to add the path:
Dir.glob('./helpers/subhelpers/*.rb').each do |file|
require File.expand_path File.join( File.dirname(__FILE__), "./helpers/subhelpers/", file)
end
will probably fix it.

Passing values from Capistrano deploy.rb file to app

In my Capistrano's deploy.rb file, I set up different environments such as server names, ports, etc. I also require the users to send a callback to another server, also defined in the deploy.rb. How do I cleanly pass this value to my app?
Something to this effect:
config/deploy.rb:
set :callback_url, "http://somecallbackurl.com:12345/bla"
app/controllers/myapp.rb:
def get_callback_url
???
end
I'm using Sinatra.
I found a solution, and that is to use the environment variables.
Set it from deploy.rb
run "export CALLBACK_URL=#{callback_url}"
From app:
def get_callback_url
ENV['CALLBACK_URL']
end
I wouldn't say it's the cleanest solution, but it works.
I'd probably recommend using a shared YAML file to store this kind of configuration, and loading it separately. For example, have a file named something like config/settings.yml, containing something like:
:callback_url: "http://somecallbackurl.com:12345/bla"
In config/deploy.rb, you could have:
settings = YAML.load_file('config/settings.yml')
set :callback_url, settings[:callback_url]
And in config/initializers/settings.rb, you could have:
settings = YAML.load_file('config/settings.yml')
CALLBACK_URL = settings[:callback_url]
Finally, in app/controllers/myapp.rb, you would do:
def get_callback_url
CALLBACK_URL
end
Using a shared YAML file is just the first thing I thought of. Another approach would be defining some constants in a ruby file, and requiring that file both in an initializer, and in deploy.rb. The basic idea is that you don't really want your app to depend on your capistrano environment, so you should find a way to separate the shared configuration.

render individual file in middleman

I am writing a helper and I need to get a rendered file as String.
I see that the method that I need exists in the middleman's library: http://rubydoc.info/github/middleman/middleman/Middleman/CoreExtensions/Rendering/InstanceMethods#render_individual_file-instance_method
How do I call this function from my helper class?
I tried:
require "middleman-core/lib/middleman-core/core_extensions/rendering.rb"
...
puts Middleman::CoreExtensions::Rendering::InstanceMethods.render_individual_file(filepath)
But it does not seem to find the file, any idea?
I'm not sure 3.0 beta is quite ready for primetime.
That said, it does sound like the partial method is what you're looking for.
Unless I'm missing something, the Middleman method seems like an overly-complex solution. For one of my sites I wanted to load entire text files into my templates, so I wrote this helper:
# Shortcut for loading raw text files. Obviously assumes that given file is in a valid format.
# #return [String] File contents
def load_textfile(filename)
File.read filename.to_s
end
Also, you should clarify if you are intending to use this within a template, or within Ruby code. It's not clear to me based on your question.
Here is an example of how one would use above helper:
Currently of note, Middleman is in the process of transitioning to version 4, and the conventions for loading helpers will change. The most straightforward way to define a helper is within a helper block in your config.rb file, as follows:
helpers do
# Define helper functions here to make them available in templates
end
I use Slim for templating. It really is the best. In slim you would appply helper as thus:
= load_textfile 'path'
p You can embed helper output in your page with interpolation, too: #{load_textfile 'path'}

Partial HAML templating in Ruby without Rails

I really don’t need the overhead of Rails for my very small project, so I’m trying to achieve this just using just plain Ruby and HAML.
I want to include another HAML file inside my HAML template. But I haven’t found a good—or really usable—way of doing this.
For example, I have these two HAML files:
documents.haml
%html
%body
= include(menu.haml) body
%article …
menu.haml
%ul
%li
%a whatever …
Include is obviously not the way to go here. But it does a nice job describing what I’m trying to achieve in this example.
I totally recommend the Tilt gem for these things. It provides a standard interface for rendering many different template langages with the same API, lets you set custom scope and locals, lets you use yield, and is robust and fast. Sinatra is using it for templates.
Example:
require 'haml'
require 'tilt'
template = Tilt.new('path/to/file.haml')
# => #<Tilt::HAMLTemplate #file="path/to/file.haml" ...>
layout = Tilt.new('path/to/layout.haml')
output = layout.render { template.render }
This lets you yield inside the layout to get the rendered template, just like Rails. As for partials, David already described a simple and nice way to go.
But actually, if what you're writing is going to be served over HTTP, i suggest you take a look at Sinatra, which already provides templating, and has the simplest request routing you could imagine.
I've done this before, just for a quick-and-dirty template producer. The easiest way is to just render the HAML inside the parent object:
%p some haml that's interesting
= Haml::Engine.new('%p this is a test').render
%p some more template
You'll more than likely want to build some methods to make this easier--a couple of helper methods. Maybe you write one called render_file that takes a filename as an argument. That method might look something like:
def render_file(filename)
contents = File.read(filename)
Haml::Engine.new(contents).render
end
Then, your template would look more like:
%p some template
= render_file('some_filename.haml')
%p more template
Note, you will probably need to pass self to the original Haml::Engine render so that it knows how to find your render_file method.
I've had great success just using the instructions posted by David Richards in a concatenated way, without variables, like this:
= Haml::Engine.new(File.read('/Volumes/Project/file_to_include.haml')).render
There's obviously a more elegant way. But for someone who just wants to include one or two files, this should work nicely. It's a drawback that all base files using these includes have to be recompiled after some changes to the latter. It might be worthwile to just use php include if the environment allows that.
def render_file(filename)
contents = File.read('views/'+filename)
Haml::Engine.new(contents).render
end
(Adding this semi-redundant answer to show how one might incorporate the techniques from other answers.)
Include something like this in your setup code to monkey-patch the Haml library.
module Haml::Helpers
def render_haml(filename)
contents = File.read(Rails.root.join("app", "assets", "templates", filename))
Haml::Engine.new(contents).render
end
end
Then in your Haml file
.foo
= render_haml('partial.haml')
.bar
Obviously this is a Rails-ish example (because I wanted to use HAML in my asset pipeline instead of as views)... You will want to replace Rails.root.join(...) with a way to find filename in your project's templates or partials directory.

Resources