Proc metaprogramming tricks?


#1

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?


#2

On Oct 19, 1:00 pm, Adam S. removed_email_address@domain.invalid 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.


#3

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:


#4

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.


#5

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


#6

On Oct 19, 2008, at 23:40, Adam S. 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 S.


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


#7

On Oct 19, 5:18 pm, Adam S. removed_email_address@domain.invalid 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 :slight_smile:

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.


#8

2008/10/19 Adam S. removed_email_address@domain.invalid:

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