Forum: Ruby Proc metaprogramming tricks?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
329f6728226e139a7b0b3b124e9b7044?d=identicon&s=25 Adam Skobi (Guest)
on 2008-10-19 19:01
(Received via mailing list)
Hi,

I'm building a DSL and trying some weird syntax structures. My DSL
should look like this.

class Root
  def dsl(&block)
    instance_eval(&block)
  end
end

class C
  #...
end


#DSL

dsl {
  met1

  class C1 < C
    #...
  end

  met2
}

Is there a way that the class C1 won't be defined inside class Root
but inside C (or somewhere else)? Maybe there is a trick in Ruby (hook
method?) so that the class C1 won't be created in Root at all and than
I could pass the block somewhere else for creation?
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Thomas Sawyer (7rans)
on 2008-10-19 22:51
(Received via mailing list)
On Oct 19, 1:00 pm, Adam Skobi <dxm...@gmail.com> wrote:
> Hi,
>
> I'm building a DSL and trying some weird syntax structures. My DSL
> should look like this.

    def dsl(&block)
      C.module_eval(&block)
    end

T.
329f6728226e139a7b0b3b124e9b7044?d=identicon&s=25 Adam Skobi (Guest)
on 2008-10-19 23:24
(Received via mailing list)
>> I'm building a DSL and trying some weird syntax structures. My DSL
>> should look like this.

>     def dsl(&block)
>       C.module_eval(&block)
>     end

Well yeah, that would work. But I was thinking about something more
general.

class Root
  def dsl(&block)
    instance_eval(&block)
  end
end

class C
  #...
end

class D
  #...
end

dsl {
  met1

  class C1 < C
    #...
  end

  class D1 < D
    #...
  end

}

Can I run part of the Proc in the context of C and part in the
context of D i.e. can I somehow split the Proc or convert it to a
readable String?

The more I think about it, the more absurd the reasoning behind it
seems. But since I'm at it, I may as well continue the debate :-)
D71ee781fc01856cc187c3ce14374c80?d=identicon&s=25 Mikael Høilund (Guest)
on 2008-10-19 23:33
(Received via mailing list)
class C
   def self.inherited(klass)
     klass_name = klass.name[/[^:]+$/]
     klass.to_s.split(/::/)[0...-1].inject(Object) { |const, name|
       const.const_get name
     }.send :remove_const, klass_name
     C.const_set klass_name, klass
   end
end

NB: Don't do this.
329f6728226e139a7b0b3b124e9b7044?d=identicon&s=25 Adam Skobi (Guest)
on 2008-10-19 23:42
(Received via mailing list)
> class C
>    def self.inherited(klass)
>      klass_name = klass.name[/[^:]+$/]
>      klass.to_s.split(/::/)[0...-1].inject(Object) { |const, name|
>        const.const_get name
>      }.send :remove_const, klass_name
>      C.const_set klass_name, klass
>    end
> end

> NB: Don't do this.

Yes! Why haven't I thought of this solution?!
Thanks for that one.

Are the any non obvious reasons as why not to do this type of trick
(code obfuscation, maintance hell etc.)?
D71ee781fc01856cc187c3ce14374c80?d=identicon&s=25 Mikael Høilund (Guest)
on 2008-10-19 23:50
(Received via mailing list)
On Oct 19, 2008, at 23:40, Adam Skobi wrote:

>
>> NB: Don't do this.
>
> Yes! Why haven't I thought of this solution?!
> Thanks for that one.
>
> Are the any non obvious reasons as why not to do this type of trick
> (code obfuscation, maintance hell etc.)?
>

That, and

--8<----
class Ddddd < C
end

Ddddd.some_method # !> NameError
--8<----

Also, my roommate laughed uncontrollably the whole time I wrote that
snippet.

> --
> Adam Skobi
>
>

--
a,b=%Q=Z,O^NPO\r4_PV\\PI\x15^-\x0\v=,email=%\%%%c\%115%%# Mikael
Hoilund, CTO
okay=%#;hmm=(0...a.size).map{|i|((a[i]-email[i]+2)%128).# of Meta.io
ApS from
chr}.join;!email.gsub!'o',"%c%c"%[3+?0.<<(2),?G.~@];aha=#############
Denmark
hmm.scan(/#{'(.)'*5}/);!puts(email[1..-12]+aha.shift.zip(*aha).join)#
Ruby <3
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Thomas Sawyer (7rans)
on 2008-10-20 04:42
(Received via mailing list)
On Oct 19, 5:18 pm, Adam Skobi <dxm...@gmail.com> wrote:
>   def dsl(&block)
> end
>   end
>
> }
>
> Can I run part of the Proc in the context of C and part in the
> context of D i.e. can I somehow split the Proc or convert it to a
> readable String?
>
> The more I think about it, the more absurd the reasoning behind it
> seems. But since I'm at it, I may as well continue the debate :-)

You can just allow them to be defined in Root and then use #inherited
to set

  C::C1 = Root:C1
  D::D1 = Root:D1
  ...

(using const_get and const_set)

T.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2008-10-20 10:34
(Received via mailing list)
2008/10/19 Adam Skobi <dxm997@gmail.com>:
>
>> NB: Don't do this.
>
> Yes! Why haven't I thought of this solution?!
> Thanks for that one.
>
> Are the any non obvious reasons as why not to do this type of trick
> (code obfuscation, maintance hell etc.)?

Yes, there's a reason: it does not work:

10:17:43 Temp$ ruby mod.rb
initial
A::X
A::X
after remove
A::X
A::X
after set
A::X
A::X
10:17:51 Temp$ cat mod.rb
module A
  class X
  end
end
$cl = ::A::X
puts "initial", $cl, $cl.name
A.send :remove_const, 'X'
puts "after remove", $cl, $cl.name
module B
end
B.send :const_set, 'Y', $cl
puts "after set", $cl, $cl.name
10:18:08 Temp$

Here's one way to do it:

class Root
  # features all objects of dsl share
  class Object
    def my_name
      # silly example
      self.class.name
    end
  end

  class <<self
    def class_def(name, parent = Object, &b)
      parent = const_get(parent) unless Module === parent
      cl = Class.new parent
      const_set name, cl
      cl.class_eval(&b)
      cl
    end
  end
end

def Object.const_missing(sym)
  Root.send :const_get, sym
end

def dsl(&b)
  Root.class_eval(&b)
end

dsl {
  class_def :Base do
    def hello() puts "Hello, I am #{my_name}." end
  end

  class_def :Derived, Base do
    # nothing here
  end

  Derived.new.hello

  p Derived.ancestors
}


Cheers

robert
This topic is locked and can not be replied to.