Class: Class
- Defined in:
- lib/jinx/import/java.rb,
lib/jinx/helpers/class.rb
Constant Summary collapse
- OBJ_INST_MTHDS =
Object.instance_methods
Class Method Summary collapse
-
.to_ruby(class_or_name) ⇒ Class
Returns the Ruby class for the given class, as follows: * If the given class is already a Ruby class, then return the class.
-
.to_ruby_name(jname) ⇒ String
private
The JRuby class or module name.
Instance Method Summary collapse
-
#abstract? ⇒ Boolean
Whether this is a wrapper for an abstract Java class.
-
#alias_attribute(aliaz, attribute) ⇒ Object
private
Creates an alias for each accessor method of the given attribute.
-
#attr_create_on_demand_accessor(symbol) {|obj| ... } ⇒ Object
private
Defines an instance variable accessor attribute whose reader calls the block given to this method to create a new instance variable on demand, if necessary.
-
#class_hierarchy ⇒ Object
Returns an Enumerable on this class and its ancestors.
-
#each_class_in_hierarchy {|klass| ... } ⇒ Object
private
Enumerates each class in the hierarchy.
-
#java_class? ⇒ Boolean
Returns whether this is a Java wrapper class.
-
#offset_attr_accessor(hash, offset = nil) ⇒ Object
private
Creates new accessor methods for each method => original hash entry.
-
#property_descriptors(hierarchy = true) ⇒ Object
Returns this class’s readable and writable Java PropertyDescriptors, or an empty Array if none.
-
#property_read_method(pd) ⇒ Symbol
The property descriptor pd introspected or discovered Java read Method.
-
#redefine_method(method) {|old_method| ... } ⇒ Symbol
private
Redefines method using the given block.
-
#transient?(pd) ⇒ Boolean
Returns whether the given PropertyDescriptor pd corresponds to a transient field in this class, or nil if there is no such field.
-
#unocclude_reserved_method(pd) ⇒ Object
Redefines the reserved method corresponding to the given Java property descriptor back to the Object implementation, if necessary.
Class Method Details
.to_ruby(class_or_name) ⇒ Class
Returns the Ruby class for the given class, as follows:
-
If the given class is already a Ruby class, then return the class.
-
If the class argument is a Java class or a Java class name, then the Ruby class is the JRuby wrapper for the Java class.
217 218 219 220 221 222 223 |
# File 'lib/jinx/import/java.rb', line 217 def self.to_ruby(class_or_name) case class_or_name when Class then class_or_name when String then eval to_ruby_name(class_or_name) else to_ruby(class_or_name.name) end end |
.to_ruby_name(jname) ⇒ String (private)
Returns the JRuby class or module name.
322 323 324 325 326 327 328 |
# File 'lib/jinx/import/java.rb', line 322 def self.to_ruby_name(jname) path = jname.split('.') return "Java::#{jname}" if path.size == 1 cname = path[-1] pkg = path[0...-1].map { |s| s.capitalize_first }.join "Java::#{pkg}::#{cname}" end |
Instance Method Details
#abstract? ⇒ Boolean
Returns whether this is a wrapper for an abstract Java class.
226 227 228 |
# File 'lib/jinx/import/java.rb', line 226 def abstract? java_class? and Java::JavaLangReflect::Modifier.isAbstract(java_class.modifiers) end |
#alias_attribute(aliaz, attribute) ⇒ Object (private)
Creates an alias for each accessor method of the given attribute.
30 31 32 33 34 |
# File 'lib/jinx/helpers/class.rb', line 30 def alias_attribute(aliaz, attribute) alias_method(aliaz, attribute) if method_defined?(attribute) writer = "#{attribute}=".to_sym alias_method("#{aliaz}=".to_sym, writer) if method_defined?(writer) end |
#attr_create_on_demand_accessor(symbol) {|obj| ... } ⇒ Object (private)
Defines an instance variable accessor attribute whose reader calls the block given to this method to create a new instance variable on demand, if necessary.
For example, the declaration
class AlertHandler
attr_create_on_demand_accessor(:pings) { Array.new }
end
is equivalent to:
class AlertHandler
attr_writer :pings
def pings
instance_variable_defined?(@pings) ? @pings : Array.new
end
end
This method is useful either as a short-hand for the create-on-demand idiom as shown in the example above, or when it is desirable to dynamically add a mix-in attribute to a class at runtime whose name is not known when the class is defined.
94 95 96 97 98 99 100 101 102 |
# File 'lib/jinx/helpers/class.rb', line 94 def attr_create_on_demand_accessor(symbol) attr_writer(symbol) wtr = "#{symbol}=".to_sym iv = "@#{symbol}".to_sym # the attribute reader creates a new proxy on demand define_method(symbol) do instance_variable_defined?(iv) ? instance_variable_get(iv) : send(wtr, yield(self)) end end |
#class_hierarchy ⇒ Object
Returns an Enumerable on this class and its ancestors.
5 6 7 |
# File 'lib/jinx/helpers/class.rb', line 5 def class_hierarchy @class__hierarchy ||= Enumerable::Enumerator.new(self, :each_class_in_hierarchy) end |
#each_class_in_hierarchy {|klass| ... } ⇒ Object (private)
Enumerates each class in the hierarchy.
108 109 110 111 112 113 114 |
# File 'lib/jinx/helpers/class.rb', line 108 def each_class_in_hierarchy current = self until current.nil? yield current current = current.superclass end end |
#java_class? ⇒ Boolean
Returns whether this is a Java wrapper class.
206 207 208 |
# File 'lib/jinx/import/java.rb', line 206 def java_class? method_defined?(:java_class) end |
#offset_attr_accessor(hash, offset = nil) ⇒ Object (private)
Creates new accessor methods for each method => original hash entry. The new method offsets the existing Number original attribute value by the given offset (default -1).
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/jinx/helpers/class.rb', line 47 def offset_attr_accessor(hash, offset=nil) offset ||= -1 hash.each do |method, original| define_method(method) { value = send(original); value + offset if value } if method_defined?(original) original_writer = "#{original}=".to_sym if method_defined?(original_writer) then define_method("#{method}=".to_sym) do |value| adjusted = value - offset if value send(original_writer, adjusted) end end end end |
#property_descriptors(hierarchy = true) ⇒ Object
Returns this class’s readable and writable Java PropertyDescriptors, or an empty Array if none. If the hierarchy flag is set to false
, then only this class’s properties will be introspected.
244 245 246 247 248 |
# File 'lib/jinx/import/java.rb', line 244 def property_descriptors(hierarchy=true) return Array::EMPTY_ARRAY unless java_class? info = hierarchy ? Java::JavaBeans::Introspector.getBeanInfo(java_class) : Java::JavaBeans::Introspector.getBeanInfo(java_class, java_class.superclass) info.propertyDescriptors.select { |pd| pd.write_method and property_read_method(pd) } end |
#property_read_method(pd) ⇒ Symbol
Returns the property descriptor pd introspected or discovered Java read Method.
306 307 308 309 310 311 312 |
# File 'lib/jinx/import/java.rb', line 306 def property_read_method(pd) return pd.read_method if pd.read_method return unless pd.get_property_type == Java::JavaLang::Boolean.java_class rdr = java_class.java_method("is#{pd.name.capitalize_first}") rescue nil logger.debug { "Discovered #{qp} #{pd.name} property non-introspected reader method #{rdr.name}." } if rdr rdr end |
#redefine_method(method) {|old_method| ... } ⇒ Symbol (private)
Redefines method using the given block. The block argument is a new alias for the old method. The block creates a proc which implements the new method body.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/jinx/helpers/class.rb', line 125 def redefine_method(method) # make a new alias id method__base for the existing method. # disambiguate with a counter suffix if necessary. counter = 2 # make a valid alias base old, eq = /^([^=]*)(=)?$/.match(method.to_s).captures old.tr!('|', 'or') old.tr!('&', 'and') old.tr!('+', 'plus') old.tr!('*', 'mult') old.tr!('/', 'div') old.gsub!(/[^\w]/, 'op') base = "redefined__#{old}" old_id = "#{base}#{eq}".to_sym while method_defined?(old_id) base = "#{base}#{counter}" old_id = "#{base}#{eq}".to_sym counter = counter + 1 end alias_method(old_id, method) body = yield old_id define_method(method, body) old_id end |
#transient?(pd) ⇒ Boolean
Returns whether the given PropertyDescriptor pd corresponds to a transient field in this class, or nil if there is no such field.
231 232 233 234 235 236 237 238 239 |
# File 'lib/jinx/import/java.rb', line 231 def transient?(pd) begin field = java_class.declared_field(pd.name) rescue Exception # should occur only if a property is not a field; not an error return end Java::JavaLangReflect::Modifier.isTransient(field.modifiers) if field end |
#unocclude_reserved_method(pd) ⇒ Object
Redefines the reserved method corresponding to the given Java property descriptor back to the Object implementation, if necessary. If both this class and Object define a method with the given property name, then a new method is defined with the same body as the previous method. Returns the new method symbol, or nil if the property name is not an occluded Object instance method.
This method undoes the JRuby clobbering of Object methods by Java property method wrappers. The method is renamed as follows:
-
id
is changed to :identifier -
type
is prefixed by the underscore subject class name, e.g. Specimen.type => :specimen_type, If the property name istype
and the subject class name ends in ‘Type’, then the property symbol is the underscore subject class name, e.g. HistologicType.type => :histologic_type.
Raises ArgumentError if symbol is not an Object method.
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/jinx/import/java.rb', line 265 def unocclude_reserved_method(pd) oldname = pd.name.underscore return unless OBJ_INST_MTHDS.include?(oldname) oldsym = oldname.to_sym undeprecated = case oldsym when :id then :object_id when :type then :class else oldsym end rsvd_mth = Object.instance_method(undeprecated) base = self.qp.underscore newname = if oldname == 'id' then 'identifier' elsif base[-oldname.length..-1] == oldname then base else "#{base}_#{oldname}" end newsym = newname.to_sym rdr = property_read_method(pd).name.to_sym alias_method(newsym, rdr) # alias the writers wtr = pd.write_method.name.to_sym alias_method("#{newsym}=".to_sym, wtr) # alias a camel-case Java-style method if necessary altname = newname.camelize unless altname == newname then alias_method(altname.to_sym, oldsym) alias_method("#{altname}=".to_sym, wtr) end # restore the old method to Object define_method(oldsym) { |*args| rsvd_mth.bind(self).call(*args) } newsym end |