tfpt review “/shelveset:ClrMemberEnumeration;REDMOND\tomat”
Implements CLR member enumeration: methods Module#methods,
instance_methods, etc. now include CLR member names.
Adds IronRuby::Clr::Name class, which represents a pair of names of a
CLR method - the primary name is mangled (Ruby name) the alternative
name is the actual CLR name.
Reflection methods like Module#instance_methods return instances of
ClrName whenever a CLR member is encountered that could be called by
both names. ClrName has methods to_s, to_sym, to_str, <=>, inspect,
dump so that it can be used wherever a string can be used. The display
string for the name uses single quotes so that you can easily
distinguish CLR (dual) names from regular names (plain mutable strings).
System::Byte.instance_methods(false)
=> ["-", “%”, “&”, “*”, “**”, “/”, “-@”, “[]”, “^”, “|”, “~”, “+”, “<”,
“<<”, “<=”, “<=>”, “==”, “>”, “>=”, “>>”, “abs”,
“div”, “divmod”, “modulo”, “quo”, “to_f”, “to_s”, “zero?”, “size”,
‘compare_to’, ‘equals’, ‘get_hash_code’, ‘to_string’, ‘get_type_code’]l = System::Byte.instance_methods(false).last
=> ‘get_type_code’l.ruby_name
=> “get_type_code”l.clr_name
=> “GetTypeCode”
Now this works with meta-programming as well:
class System::Decimal
instance_methods(false).each do |name|
mangled = ‘__’ + name
alias_method(mangled, name)
private mangled
define_method(name) do |*args|
puts "method called: #{name}"
send mangled, *args
end
end
end
x, y = System::Decimal.new(1), System::Decimal.new(2)
p x + y # => “method called: +”
p x.CompareTo(y) # => “method called: compare_to”
The trick here is in new set of define_method overloads strongly typed
to ClrName that define the real method using the ruby_name and alias it
using the clr_name. So both CompareTo and compare_to calls are
intercepted.
We might add similar overloads to other methods to improve
meta-programming experience for CLR types when needed.
Note that instance_methods never returns any ClrNames for a built-in
class or module, although some built-ins expose CLR members. The reason
is that built-ins are restricted to do no name-mangling in order to
prevent conflicts with Ruby. The CLR methods are only exposed via their
actual names.
Thread.instance_methods(false).sort
=> [“Abort”, “ApartmentState”, “ApartmentState=”, “CurrentCulture”,
“CurrentCulture=”, “CurrentUICulture”, “CurrentUICul
ture=”, “ExecutionContext”, “GetApartmentState”, “GetCompressedStack”,
“GetHashCode”, “Interrupt”, “IsAlive”, “IsBackgro
und”, “IsBackground=”, “IsThreadPoolThread”, “Join”, “ManagedThreadId”,
“Name”, “Name=”, “Priority”, “Priority=”, “Resum
e”, “SetApartmentState”, “SetCompressedStack”, “Start”, “Suspend”,
“ThreadState”, “TrySetApartmentState”, “[]”, “[]=”, "
abort_on_exception", “abort_on_exception=”, “alive?”, “exit”, “group”,
“inspect”, “join”, “key?”, “keys”, “kill”, "raise
", “run”, “status”, “stop?”, “terminate”, “value”, “wakeup”]
Tomas