Reputation: 1469
This is my first time making a custom rails generator and I want to be able to create a dynamic class in the template based off the argument passed to the generator but I can't figure out how and to have it formatted properly.
class Achievements::__FILE__ < Achievement
end
This is the generated class I want to create and below is the generator. Also on a side note, am I creating the directory 'achievement' right in my generator?
module Achiever
module Generators
class AchievementGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)
argument :award, :type => :string
def generate_achievement
copy_file "achievement.rb", "app/models/achievement/#{file_name}.rb"
end
private
def file_name
award.underscore
end
end
end
end
Upvotes: 2
Views: 2037
Reputation: 1469
I figured out the problem with this issue. Instead of the copy_file method I should be using the template method. This then allows me to use erb tags inside the templated view and I can call the file_name.classify inside the views and it will dynamically create the model.
argument :award, :type => :string
What ever is set here above as the argument will define the class below in the generated model.
class Achievements::<%= file_name.classify %> < Achievement
end
Upvotes: 0
Reputation: 3634
Use Module#const_set. It is automatically included into Object, so you can do things like:
foo.rb
# Defining the class dynamically. Note that it doesn't currently have a name
klass = Class.new do
attr_accessor(:args)
def initialize(*args)
@stuff = args
end
end
# Getting the class name
class_name = ARGV[0].capitalize
# Assign it to a constant... dynamically. Ruby will give it a name here.
Object.const_set(class_name, klass)
# Create a new instance of it, print the class's name, and print the arguments passed to it. Note: we could just use klass.new, but this is more fun.
my_klass = const_get(class_name).new(ARGV[1..-1])
puts "Created new instance of `" << my_klass.class << "' with arguments: " << my_klass.args.join(", ")
I haven't tried this code out yet, but it should produce something like:
$ ruby foo.rb RubyRules pancakes are better than waffles
Created new instance of `RubyRules' with arguments: pancakes, are, better, than, waffles
Also, the first argument to const_set
absolutely must begin with a capitalized alphanumeric character (just like defining constants statically), or Ruby will produce an error something along the lines of:
NameError: wrong constant name rubyRules
--- INSERT STACKTRACE HERE ---
Upvotes: 2