How to factor this code (not trivial)

Hi,

I’m having trouble to factor some simple code. Since, I have been stuck
for
several days now I ask the question here.

Beginning of code

module DefWithName
def integer(name, options = {})
store_result name, MyInteger.new(options)
end

def id(name)
integer(name, an_options: true)
end
end

module DefWithoutName
def integer(options = {})
store_result MyInteger.new(options)
end

def id
integer(an_options: true)
end
end

class A; include DefWithName; end
class AA; include DefWithName; end
class B; include DefWithoutName; end
class BB; include DefWithoutName; end

End of code

Constraints:

  • The “id” function has to call “integer” and not “store_result” because
    it
    may be defined as a plugin.
  • The functions must still raise ArgumentError as they already do.

Any ideas?

Regards,
-Nico

On Monday, March 4, 2013 12:59:23 PM UTC, Nicolas D. wrote:

Hi,

Constraints:

  • The “id” function has to call “integer” and not “store_result” because it may
    be defined as a plugin.
  • The functions must still raise ArgumentError as they already do.

Could you give some examples of what you’re trying to do or problems
you’ve run into? You’ve posted some code but haven’t described how
you’ll be using it and in what way it isn’t adequate.In fewer words: I
don’t see what your question is.

Fred

On Mon, Mar 4, 2013 at 7:36 PM, Frederick C.
<[email protected]

wrote:

Could you give some examples of what you’re trying to do or problems
you’ve run into? You’ve posted some code but haven’t described how you’ll
be using it and in what way it isn’t adequate.In fewer words: I don’t see
what your question is.

Thanks for replying.

Yes sorry. I realize that some context is missing.

I am writing an API where the users are allowed to write something

like
that:

FooContextWithName.new.eval do |o|
o.integer “id”, an_option: true # [1]
o.integer “foo”, an_option: true # [2]
o.bar “a_name” do |o|
o.integer an_option: true # [3]
end
end

I would like that users are able to factor [1] and [2] by writing a

small
plugin like this:

module MyHelpers
def id(name = “id”)
integer name, an_option: true
end
end
MyLib.add_helpers(MyHelpers) # add_helpers would be defined
appropriately

To factor [3] users should be able to write something like that:

module MyHelpers
def id
integer an_option: true
end
end

To implement this API I have something like this

module DefWithName
def integer(name, options = {})
store_result name, MyInteger.new(options)
end
end

module DefWithoutName
def integer(options = {})
store_result MyInteger.new(options)
end
end

class FooWithName < BasicObject
include DefWithName

def store_result(name, object)
@props[name] = object
end
end

class BarWithoutName < BasicObject
include DefWithoutName

def store_result(object)
@items << object
end
end

===========================
My goal is to provide a way for users to write their “id” method once
and
to work in both cases.

I am thinking about something like that:

def id(*args)
if name_required?
name = name_given? ? given_name : “id”
end

integer name, an_option: true
end

def integer(*args)
value = MyInteger.new(options)
if name_required?
if name_given?
store_result given_name, value
else
raise ArgumentError
end
else
if name_given?
raise ArgumentError
end
store_result value
end
end

where “name_required?”, “given_name” and “name_given?” would be defined
appropriately based on the arguments passed to the method.

I hope this is clearer now.


Nicolas D.

On Tue, Mar 5, 2013 at 10:37 AM, Nicolas D.
[email protected]wrote:

  • The “id” function has to call “integer” and not “store_result”

o.bar “a_name” do |o|
end

store_result MyInteger.new(options)

to work in both cases.

  raise ArgumentError

I finally found a good way to factor this.

Instead of having two modules DefWithoutName and DefWithName I have only
one:

module BasicDef
def integer(name, options = {})
store_result name, MyInteger.new(options)
end
end

Then I use a proxy for evaluation that will

  • in the case of “with name” will call directly the target method and
    pass
    it all the arguments
  • in the case of “without name” will call the target method by passing
    “nil” as first arguments and then the rest of the arguments.
    The proxy checks when the target method requires a name as first
    argument
    using the Method#parameters method.


Nicolas D.