Module: Jinx::Introspector
Overview
Meta-data mix-in to infer attribute meta-data from Java properties.
Instance Attribute Summary
Attributes included from Propertied
Instance Method Summary collapse
-
#add_attribute_value_initializer ⇒ Object
Adds an optional attribute=>value constructor parameter to this class.
-
#add_java_property(pd) ⇒ Property
private
Makes a standard attribute for the given property descriptor.
-
#alias_property_accessors(property) ⇒ Object
private
Aliases the given Ruby property reader and writer to its underlying Java property reader and writer, resp.
-
#create_java_property(pd) ⇒ Property
private
The new property.
-
#define_java_property(pd) ⇒ Object
private
Defines the Java property attribute and standard attribute methods, e.g.
-
#delegate_to_property(aliaz, property) ⇒ Object
private
Defines methods aliaz and aliaz= which calls the standard attribute and attribute= accessor methods, resp.
-
#introspect ⇒ Object
Defines the Java attribute access methods, e.g.
-
#introspected? ⇒ Boolean
Whether this class has been introspected.
-
#wrap_java_date_property(property) ⇒ Object
private
Adds a Java-Ruby Date filter to the given Date property Ruby access methods.
-
#wrap_java_property(property) ⇒ Object
private
Adds a filter to the given property access methods if it is a String or Date.
-
#wrap_java_string_property(property) ⇒ Object
private
Adds a number -> string filter to the given String property Ruby access methods.
Methods included from Propertied
#add_alternate_key_attribute, #add_attribute, #add_attribute_aliases, #add_attribute_default, #add_attribute_defaults, #add_mandatory_attribute, #add_mandatory_attributes, #add_primary_key_attribute, #add_property, #add_restriction, #add_secondary_key_attribute, #alias_attribute, #alias_standard_attribute_hash, #all_key_attributes, #alternate_key_attributes, #append_ancestor_enum, #attribute_filter, #collect_mandatory_attributes, #collection_attribute?, #create_nonjava_property, #default_mandatory_local_attributes, #dependent_attributes, #detect_attribute_with_type, #domain_attribute?, #domain_attributes, #each_property, #independent_attributes, #init_property_classifiers, #java_attributes, #mandatory_attributes, #mandatory_owner_attribute, #most_specific_domain_attribute, #nondomain_attribute?, #nondomain_attributes, #nondomain_java_attributes, #nonowner_attributes, #offset_attribute, #primary_key_attributes, #property, #property_defined?, #property_hash, #property_path, #qualify_attribute, #register_property_alias, #remove_attribute, #secondary_key_attributes, #secondary_key_non_owner_domain_attributes, #set_alternate_key_attributes, #set_attribute_type, #set_primary_key_attributes, #set_secondary_key_attributes, #standard_attribute, #unidirectional_dependent_attributes
Instance Method Details
#add_attribute_value_initializer ⇒ Object
Adds an optional attribute=>value constructor parameter to this class.
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/jinx/metadata/introspector.rb', line 18 def add_attribute_value_initializer class << self def new(params=nil) obj = super() obj.merge_attributes(params) if params obj end end logger.debug { "#{self} is extended with an optional {attribute=>value} constructor parameter." } end |
#add_java_property(pd) ⇒ Property (private)
Makes a standard attribute for the given property descriptor. Adds a camelized Java-like alias to the standard attribute.
153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/jinx/metadata/introspector.rb', line 153 def add_java_property(pd) # make the attribute metadata prop = create_java_property(pd) add_property(prop) # the property name is an alias for the standard attribute pa = prop.attribute # the Java property name as an attribute symbol ja = pd.name.to_sym delegate_to_property(ja, prop) unless prop.reader == ja prop end |
#alias_property_accessors(property) ⇒ Object (private)
Aliases the given Ruby property reader and writer to its underlying Java property reader and writer, resp.
140 141 142 143 144 145 146 |
# File 'lib/jinx/metadata/introspector.rb', line 140 def alias_property_accessors(property) # the Java reader and writer accessor method symbols jra, jwa = property.java_accessors # strip the Java reader and writer is/get/set prefix and make a symbol alias_method(property.reader, jra) alias_method(property.writer, jwa) end |
#create_java_property(pd) ⇒ Property (private)
Returns the new property.
167 168 169 |
# File 'lib/jinx/metadata/introspector.rb', line 167 def create_java_property(pd) JavaProperty.new(pd, self) end |
#define_java_property(pd) ⇒ Object (private)
Defines the Java property attribute and standard attribute methods, e.g. study_protocol
and studyProtocol
. A boolean attribute is provisioned with an additional reader alias, e.g. available?
for is_available
.
A standard attribute which differs from the property attribute delegates to the property attribute, e.g. study_protocol
delegates to studyProtocol
rather than aliasing setStudyProtocol
. Redefining these methods results in a call to the redefined method. This contrasts with a Ruby alias, where each attribute alias is bound to the respective attribute reader or writer.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/jinx/metadata/introspector.rb', line 75 def define_java_property(pd) if transient?(pd) then logger.debug { "Ignoring #{name.demodulize} transient attribute #{pd.name}." } return end # the standard underscore lower-case attributes prop = add_java_property(pd) # delegate the standard attribute accessors to the attribute accessors alias_property_accessors(prop) # add special wrappers wrap_java_property(prop) # create Ruby alias for boolean, e.g. alias :empty? for :empty if pd.property_type.name[/\w+$/].downcase == 'boolean' then # Strip the leading is_, if any, before appending a question mark. aliaz = prop.to_s[/^(is_)?(\w+)/, 2] << '?' delegate_to_property(aliaz, prop) end end |
#delegate_to_property(aliaz, property) ⇒ Object (private)
Defines methods aliaz and aliaz= which calls the standard attribute and attribute= accessor methods, resp. Calling rather than aliasing the attribute accessor allows the aliaz accessor to reflect a change to the attribute accessor.
175 176 177 178 179 180 181 |
# File 'lib/jinx/metadata/introspector.rb', line 175 def delegate_to_property(aliaz, property) ra, wa = property.accessors if aliaz == ra then raise MetadataError.new("Cannot delegate #{self} #{aliaz} to itself.") end define_method(aliaz) { send(ra) } define_method("#{aliaz}=".to_sym) { |value| send(wa, value) } register_property_alias(aliaz, property.attribute) end |
#introspect ⇒ Object
Defines the Java attribute access methods, e.g. study_protocol
and studyProtocol
. A boolean attribute is provisioned with an additional reader alias, e.g. available?
for is_available
.
Each Java property attribute delegates to the Java attribute getter and setter. Each standard attribute delegates to the Java property attribute. Redefining these methods results in a call to the redefined method. This contrasts with a Ruby alias, where the alias remains bound to the original method body.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/jinx/metadata/introspector.rb', line 38 def introspect # Set up the attribute data structures; delegates to Propertied. init_property_classifiers logger.debug { "Introspecting #{qp} metadata..." } # check for method conflicts conflicts = instance_methods(false) & Resource.instance_methods(false) unless conflicts.empty? then logger.warn("#{self} methods conflict with #{Resource} methods: #{conflicts.qp}") end # If this is a Java class rather than interface, then define the Java property # attributes. if Class === self then # the Java attributes defined by this class with both a read and a write method pds = property_descriptors(false) # Define the standard Java attribute methods. pds.each { |pd| define_java_property(pd) } end # Mark this class as introspected. @introspected = true logger.debug { "Introspection of #{qp} metadata complete." } self end |
#introspected? ⇒ Boolean
Returns whether this class has been introspected.
13 14 15 |
# File 'lib/jinx/metadata/introspector.rb', line 13 def introspected? !!@introspected end |
#wrap_java_date_property(property) ⇒ Object (private)
Adds a Java-Ruby Date filter to the given Date property Ruby access methods. The reader returns a Ruby date. The writer sets a Java date.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/jinx/metadata/introspector.rb', line 118 def wrap_java_date_property(property) ra, wa = property.accessors jra, jwa = property.java_accessors # filter the attribute reader define_method(ra) do value = send(jra) Java::JavaUtil::Date === value ? value.to_ruby_date : value end # filter the attribute writer define_method(wa) do |value| value = Java::JavaUtil::Date.from_ruby_date(value) if ::Date === value send(jwa, value) end logger.debug { "Filtered #{qp} #{ra} and #{wa} methods with Java Date <-> Ruby Date converter." } end |
#wrap_java_property(property) ⇒ Object (private)
Adds a filter to the given property access methods if it is a String or Date.
95 96 97 98 99 100 101 102 |
# File 'lib/jinx/metadata/introspector.rb', line 95 def wrap_java_property(property) pd = property.property_descriptor if pd.property_type == Java::JavaLang::String.java_class then wrap_java_string_property(property) elsif pd.property_type == Java::JavaUtil::Date.java_class then wrap_java_date_property(property) end end |
#wrap_java_string_property(property) ⇒ Object (private)
Adds a number -> string filter to the given String property Ruby access methods.
105 106 107 108 109 110 111 112 113 114 |
# File 'lib/jinx/metadata/introspector.rb', line 105 def wrap_java_string_property(property) ra, wa = property.accessors jra, jwa = property.java_accessors # filter the attribute writer define_method(wa) do |value| stdval = Math.numeric?(value) ? value.to_s : value send(jwa, stdval) end logger.debug { "Filtered #{qp} #{wa} method with non-String -> String converter." } end |