Proc metaprogramming tricks?

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?

···

--
Adam Skobi

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

T.

···

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.

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 :slight_smile:

···

--
Adam Skobi

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.

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.

···

On Oct 19, 5:18 pm, Adam Skobi <dxm...@gmail.com> wrote:

>> 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 :slight_smile:

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.)?

···

--
Adam Skobi

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.)?

That, and

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

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

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

···

On Oct 19, 2008, at 23:40, Adam Skobi wrote:

--
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

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.)?

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

10:17:43 Temp$ ruby mod.rb
initial
after remove
after set
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

···

2008/10/19 Adam Skobi <dxm997@gmail.com>:
A::X
A::X
A::X
A::X
A::X
A::X

--
remember.guy do |as, often| as.you_can - without end