Class: Appear::Util::Join
- Inherits:
-
Object
- Object
- Appear::Util::Join
- Defined in:
- lib/appear/util/join.rb
Overview
Class for joining objects based on hash value or method value.
Class Method Summary collapse
-
.access(obj, field) ⇒ Any
Access the given field on an object.
-
.can_access?(obj, field) ⇒ Boolean
True if we can access the given field on an object, either by calling that method on the object, or by accessing using [].
-
.join(field, *tables) ⇒ Array<Join>
Join objects or hashes together where their field values match.
Instance Method Summary collapse
-
#[](sym) ⇒ Any?
read a field from the join.
-
#initialize(*objs) ⇒ Join
constructor
A Join is a union of data objects.
-
#joined_count ⇒ Fixnum
get the number of objects in this join.
-
#method_missing(method, *args, &block) ⇒ Object
the #method_missing implementation on a Join allows you to access valid fields with regular accessors.
-
#push!(obj) ⇒ Object
add another data object to this join.
-
#respond_to?(sym, priv = false) ⇒ Boolean
True if we can respond to the given method name.
-
#unjoin {|Object| ... } ⇒ Object
Return the first member in the join that matches the given block.
Constructor Details
#initialize(*objs) ⇒ Join
A Join is a union of data objects. You can use a Join to group objects of different types, so that you may read from whichever has a given field.
It is more useful to use self.join to perform a join operation on collections than to create Join objects directly.
81 82 83 |
# File 'lib/appear/util/join.rb', line 81 def initialize(*objs) @objs = objs end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object
the #method_missing implementation on a Join allows you to access valid fields with regular accessors.
129 130 131 132 133 134 |
# File 'lib/appear/util/join.rb', line 129 def method_missing(method, *args, &block) raise NoMethodError.new("Cannot access #{method.inspect}") unless respond_to?(method) raise ArgumentError.new("Passed args to accessor") if args.length > 0 raise ArgumentError.new("Passed block to accessor") if block self[method] end |
Class Method Details
.access(obj, field) ⇒ Any
Access the given field on an object. Raises an error if the field cannot be accessed.
66 67 68 69 70 71 72 73 74 |
# File 'lib/appear/util/join.rb', line 66 def self.access(obj, field) if obj.respond_to?(field) obj.send(field) elsif obj.respond_to?(:[]) obj[field] else raise "cannot access #{field.inspect} on #{obj.inspect}" end end |
.can_access?(obj, field) ⇒ Boolean
True if we can access the given field on an object, either by calling that method on the object, or by accessing using []
51 52 53 54 55 56 57 58 |
# File 'lib/appear/util/join.rb', line 51 def self.can_access?(obj, field) if obj.respond_to?(field) return true elsif obj.respond_to?(:[]) return true end return false end |
.join(field, *tables) ⇒ Array<Join>
Join objects or hashes together where their field values match. This method is analogous to a JOIN in SQL, although the behavior is not exactly the same.
foo_bars is an array of Join instances. Reads from a foo_bar will read first from the foo, and then from the bar - this is based on the order of “tables” passed to Join.join().
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/appear/util/join.rb', line 29 def self.join(field, *tables) by_field = Hash.new { |h, k| h[k] = self.new } tables.each do |table| table.each do |row| field_value = access(row, field) joined = by_field[field_value] joined.push!(row) end end by_field.values.select do |joined| joined.joined_count >= tables.length end end |
Instance Method Details
#[](sym) ⇒ Any?
read a field from the join. Returns the first non-nil value we can read.
110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/appear/util/join.rb', line 110 def [](sym) result = nil @objs.each do |obj| if self.class.can_access?(obj, sym) result = self.class.access(obj, sym) end break unless result.nil? end result end |
#joined_count ⇒ Fixnum
get the number of objects in this join
95 96 97 |
# File 'lib/appear/util/join.rb', line 95 def joined_count @objs.length end |
#push!(obj) ⇒ Object
add another data object to this join.
88 89 90 |
# File 'lib/appear/util/join.rb', line 88 def push!(obj) @objs << obj end |
#respond_to?(sym, priv = false) ⇒ Boolean
139 140 141 |
# File 'lib/appear/util/join.rb', line 139 def respond_to?(sym, priv = false) super(sym, priv) || (@objs.any? { |o| self.class.can_access?(o, sym) }) end |
#unjoin {|Object| ... } ⇒ Object
Return the first member in the join that matches the given block.
101 102 103 |
# File 'lib/appear/util/join.rb', line 101 def unjoin(&block) @objs.find(&block) end |