Ed de Almeida Ed de Almeida - 1 year ago 81
Ruby Question

I need to initialize something I really don't know previously what it is in Ruby

Let me try to explain what I need, then maybe someone may tell me how to do it.

I have a series of entities in my system. They are listed in an array

@entities = [ :component, :email, :form, :library, :page, :project, :resource, :template ]

I parse a command line using Slop gem, then I get all parsed options in the opts hash and the remaining command line parameters in the args array.

The first element of args array is always the entity I need to create to handle the command line inputs. Let's assume, for the sake of this reasoning, that I'm creating a :project.

Now, I have a file project.rb, which contains:

entity_block = lambda { |ent|
ent.entity_type = :project
# All other initialization options

And in my main module I have the following method:

def self.start(args,opts)

# Saves arguments and options
@arguments = args
@options = opts

# Isolates the entity which will handle the command line request
@entity = @arguments[0]
exit_error(103,@entites) if not @entities.include?(@entity.to_sym)

# Requires the correct block for the entity type
require "entities/#{@entity}"

# Creates the entity class
EmeraldFW::Entity.new(@arguments,@options) do

And here is my entity.rb file:

module EmeraldFW

class Entity

attr_accessor :entity_type, :entity_base_dir

def initialize(args,opts)
@args = args
@opts = opts

def execute
puts entity_base_dir
puts "Do something..."



As you may see, what I intend to do is requiring among the
files, the file which contains the specific initial values for that specific entity.

The idea is having
, for instance, initialized after running the code. Not just his, but all other parameters needed to identify that specific entity the user mentioned at the command line.

It happens that this is not working. If it were, I wouldn't be here bothering you, of course.

I tried do use
to inject the newly created Entity object in the lambda block defined by
, like this:

EmeraldFW::Entity.new(@arguments,@options).tap do

And I also tried to do
like this?

EmeraldFW::Entity.new(@arguments,@options).tap do

Summary: My problem, then, is how to create an entity dinamically?

Of course I considered the possibility of doing something like

entity_class = "EmeraldFW::#{@entity.capitalize}".split('::').inject(Object) {|o,c| o.const_get c}.new(@arguments,@options)

But first I'd like to know if this other way is possible and what I am missing here.

By the way, this is the error I always get:

/home/edvaldo/software/github/emeraldfw21/lib/emeraldfw.rb:34:in `block in start': undefined local variable or method `entity_block' for EmeraldFW:Module (NameError)

Answer Source

if entity_block is a proc or lambda it won't be called if you just type it's name with out parenthesis (unlike a typical method, which will be called).

So I think your issue is that your block is never being called.

Try, instead, this:

entity = EmeraldFW::Entity.new(@arguments,@options)


# similarly
entity.instance_eval { entity_block.call(self) }

By the way, regarding your use of tap - It looks like you're trying to achieve some dynamic scoping, which it won't do for you. It's really just syntactic sugar for assigning a variable, if you ask me. To get dynamic scoping for a block you can use class_exec or instance_exec. However doing this is unnecessary if you're explicitly passing around objects as arguments and aren't trying to redefine self.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download