Class: Gorillib::Collection
- Defined in:
- lib/gorillib/collection.rb,
lib/gorillib/collection/model_collection.rb
Overview
The Collection class encapsulates the minimum functionality to let you:
- store items uniquely, in order added
- retrieve items by label
- iterate over its values
A collection is best used for representing 'plural' properties of models; it is not intended to be some radical reimagining of a generic array or hash. We've found its locked-down capabilities to particularly useful for constructing DSLs (Domain-Specific Languages). Collections are not intended to be performant: its abstraction layer comes at the price of additional method calls.
Gated admission
Collection provides a well-defended perimeter. Every item added to the
collection (whether sent to the initializer, the passes through add
method
Familiarity with its contents
Typically your model will have a familiar (but not intimate) relationship with its plural property:
- items may have some intrinsic, uniquely-identifying feature: a
name
,id
, or normalized representation. You'd like to be able to add an retrieve them by that intrinsic feature without having to manually juggle the correspondence of labels to intrinsic features.
In the case of a ModelCollection,
all its items may share a common type: "a post has many
Comment
s".a model may want items to hold a reference back to the containing model, or otherwise to share some common attributes. As an example, a
Graph
may have manyStage
objects; the collection can inform newly-added stages which graph they belong to.
Barebones enumerable methods
The set of methods is purposefully sparse. If you want to use select
,
invert
, etc, just invoke to_hash
or to_a
and work with the copy it
gives you.
Collection responds to:
- receive!, values, to_a, each and each_value;
- length, size, empty?, blank?
- [], []=, include?, fetch, delete, each_pair, to_hash.
key_method
: called on items to get their key;to_key
by default.<<
: adds item under itskey_method
keyreceive!
s an array by auto-keying the elements, or a hash by trusting what you give it
A ModelCollection adds:
factory
: generates new items, converts received itemsupdate_or_create: if absent, creates item with given attributes and
key_method => key`; if present, updates with given attributes.
Direct Known Subclasses
Defined Under Namespace
Modules: CommonAttrs, ItemsBelongTo
Instance Attribute Summary collapse
-
#belongs_to ⇒ Object
readonly
Object that owns this collection, if any.
Class Method Summary collapse
-
.native?(obj) ⇒ true, false
A
native
object does not need any transformation; it is accepted directly. -
.receive(items, *args) ⇒ Object
Create a new collection and add the given items to it (if given an existing collection, just returns it directly).
Instance Method Summary collapse
-
#<<(item) ⇒ Gorillib::Collection
Adds item, returning the collection itself.
-
#==(other) ⇒ true, false
Two collections are equal if they have the same class and their contents are equal.
-
#[]=(label, item) ⇒ Object
add item with given label.
-
#add(item, label = nil) ⇒ Object
Adds an item in-place.
-
#each(&block) ⇒ Object
iterate over each value in the collection.
-
#initialize(options = {}) ⇒ Collection
constructor
include Gorillib::Model.
-
#inspect ⇒ String
String describing the collection's array representation.
- #inspect_compact ⇒ Object
- #label_for(item) ⇒ Object
-
#receive!(other) ⇒ Gorillib::Collection
Receive items in-place, replacing any existing item with that label.
-
#receive_item(label, item) ⇒ Object
items arriving from the outside world should pass through receive_item, not directly to add.
-
#to_a ⇒ Array
An array holding the items.
-
#to_hash ⇒ {Symbol => Object}
A hash of key=>item pairs.
-
#to_s ⇒ String
String describing the collection's array representation.
Constructor Details
#initialize(options = {}) ⇒ Collection
include Gorillib::Model
77 78 79 80 81 |
# File 'lib/gorillib/collection.rb', line 77 def initialize(={}) @clxn = Hash.new @key_method = [:key_method] if [:key_method] @belongs_to = [:belongs_to] if [:belongs_to] end |
Instance Attribute Details
#belongs_to ⇒ Object (readonly)
Object that owns this collection, if any
70 71 72 |
# File 'lib/gorillib/collection.rb', line 70 def belongs_to @belongs_to end |
Class Method Details
.native?(obj) ⇒ true, false
A native
object does not need any transformation; it is accepted directly.
By default, an object is native if it is_a?
this class
176 177 178 |
# File 'lib/gorillib/collection.rb', line 176 def self.native?(obj) obj.is_a?(self) end |
.receive(items, *args) ⇒ Object
Create a new collection and add the given items to it (if given an existing collection, just returns it directly)
164 165 166 167 168 169 |
# File 'lib/gorillib/collection.rb', line 164 def self.receive(items, *args) return items if native?(items) coll = new(*args) coll.receive!(items) coll end |
Instance Method Details
#<<(item) ⇒ Gorillib::Collection
Adds item, returning the collection itself.
128 129 130 131 |
# File 'lib/gorillib/collection.rb', line 128 def <<(item) add(item) self end |
#==(other) ⇒ true, false
Two collections are equal if they have the same class and their contents are equal
184 185 186 187 |
# File 'lib/gorillib/collection.rb', line 184 def ==(other) return false unless other.instance_of?(self.class) clxn == other.send(:clxn) end |
#[]=(label, item) ⇒ Object
add item with given label
134 135 136 |
# File 'lib/gorillib/collection.rb', line 134 def []=(label, item) add(item, label) end |
#add(item, label = nil) ⇒ Object
Adds an item in-place. Items added to the collection (via add
, []=
,
initialize
, etc) all pass through the add
method: you should override
this in subclasses to add any gatekeeper behavior.
If no label is supplied, we use the result of invoking key_method
on the
item (or raise an error if no label and no key_method).
It's up to you to ensure that labels make sense; this method doesn't demand the item's key_method match its label.
94 95 96 97 |
# File 'lib/gorillib/collection.rb', line 94 def add(item, label=nil) label ||= label_for(item) @clxn[label] = item end |
#each(&block) ⇒ Object
iterate over each value in the collection
124 |
# File 'lib/gorillib/collection.rb', line 124 def each(&block); each_value(&block) ; end |
#inspect ⇒ String
Returns string describing the collection's array representation.
192 193 194 195 196 |
# File 'lib/gorillib/collection.rb', line 192 def inspect key_width = [keys.map{|key| key.to_s.length + 1 }.max.to_i, 45].min guts = clxn.map{|key, val| "%-#{key_width}s %s" % ["#{key}:", val.inspect] }.join(",\n ") ['c{ ', guts, ' }'].join end |
#inspect_compact ⇒ Object
198 199 200 |
# File 'lib/gorillib/collection.rb', line 198 def inspect_compact ['c{ ', keys.join(", "), ' }'].join end |
#label_for(item) ⇒ Object
99 100 101 102 103 104 |
# File 'lib/gorillib/collection.rb', line 99 def label_for(item) if key_method.nil? then raise ArgumentError, "Can't add things to a #{self.class} without some sort of label: use foo[label] = obj, or set the collection's key_method" ; end item.public_send(key_method) end |
#receive!(other) ⇒ Gorillib::Collection
Receive items in-place, replacing any existing item with that label.
Individual items are added using #receive_item -- if you'd like to perform any conversion or modification to items, do it there
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/gorillib/collection.rb', line 145 def receive!(other) if other.respond_to?(:each_pair) other.each_pair{|label, item| receive_item(label, item) } elsif other.respond_to?(:each) other.each{|item| receive_item(nil, item) } else raise "A collection can only receive something that is enumerable: got #{other.inspect}" end self end |
#receive_item(label, item) ⇒ Object
items arriving from the outside world should pass through receive_item, not directly to add.
158 159 160 |
# File 'lib/gorillib/collection.rb', line 158 def receive_item(label, item) add(item, label) end |
#to_a ⇒ Array
Returns an array holding the items.
119 |
# File 'lib/gorillib/collection.rb', line 119 def to_a ; values ; end |
#to_hash ⇒ {Symbol => Object}
Returns a hash of key=>item pairs.
121 |
# File 'lib/gorillib/collection.rb', line 121 def to_hash ; clxn.dup ; end |
#to_s ⇒ String
Returns string describing the collection's array representation.
190 |
# File 'lib/gorillib/collection.rb', line 190 def to_s ; to_a.to_s ; end |