compo 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +8 -0
- data/lib/compo/branches/array.rb +17 -0
- data/lib/compo/branches/branch.rb +35 -0
- data/lib/compo/branches/constant.rb +34 -0
- data/lib/compo/branches/hash.rb +17 -0
- data/lib/compo/branches/leaf.rb +15 -0
- data/lib/compo/branches.rb +15 -0
- data/lib/compo/composites/array.rb +105 -0
- data/lib/compo/composites/composite.rb +183 -0
- data/lib/compo/composites/hash.rb +72 -0
- data/lib/compo/composites/leaf.rb +64 -0
- data/lib/compo/composites/parentless.rb +133 -0
- data/lib/compo/composites.rb +20 -0
- data/lib/compo/finders/url.rb +166 -0
- data/lib/compo/finders.rb +10 -0
- data/lib/compo/mixins/movable.rb +55 -0
- data/lib/compo/mixins/parent_tracker.rb +74 -0
- data/lib/compo/mixins/url_referenceable.rb +70 -0
- data/lib/compo/mixins.rb +9 -0
- data/lib/compo/version.rb +1 -1
- data/lib/compo.rb +4 -21
- data/spec/array_branch_spec.rb +4 -2
- data/spec/array_composite_shared_examples.rb +2 -2
- data/spec/array_composite_spec.rb +1 -1
- data/spec/branch_shared_examples.rb +38 -5
- data/spec/branch_spec.rb +1 -1
- data/spec/composite_shared_examples.rb +1 -1
- data/spec/composite_spec.rb +1 -1
- data/spec/constant_branch_spec.rb +18 -0
- data/spec/hash_branch_spec.rb +4 -2
- data/spec/hash_composite_shared_examples.rb +3 -3
- data/spec/hash_composite_spec.rb +1 -1
- data/spec/leaf_branch_spec.rb +9 -0
- data/spec/{null_composite_shared_examples.rb → leaf_composite_shared_examples.rb} +1 -1
- data/spec/leaf_composite_spec.rb +7 -0
- data/spec/movable_shared_examples.rb +3 -3
- data/spec/movable_spec.rb +1 -1
- data/spec/parent_tracker_spec.rb +2 -15
- data/spec/parentless_spec.rb +2 -2
- data/spec/url_finder_shared_examples.rb +104 -0
- data/spec/url_finder_spec.rb +25 -114
- data/spec/url_referenceable_spec.rb +1 -1
- metadata +30 -21
- data/lib/compo/array_branch.rb +0 -16
- data/lib/compo/array_composite.rb +0 -103
- data/lib/compo/branch.rb +0 -18
- data/lib/compo/composite.rb +0 -181
- data/lib/compo/hash_branch.rb +0 -17
- data/lib/compo/hash_composite.rb +0 -70
- data/lib/compo/leaf.rb +0 -14
- data/lib/compo/movable.rb +0 -53
- data/lib/compo/null_composite.rb +0 -62
- data/lib/compo/parent_tracker.rb +0 -80
- data/lib/compo/parentless.rb +0 -131
- data/lib/compo/url_finder.rb +0 -164
- data/lib/compo/url_referenceable.rb +0 -68
- data/spec/leaf_spec.rb +0 -9
- data/spec/null_composite_spec.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a7465849db65d98eec1007ce000a7a75fa78309
|
4
|
+
data.tar.gz: 6472acc91b29bda5ba2c3886a0a50a88f28f8c74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84cfa4992537c356070d0a2885cff6bfd3e6e39050bdb6986ac413d1c6920dc05316b945e5f2e1f7fe79fc044d318d602c3a6a9befc404ca9814b622a238737e
|
7
|
+
data.tar.gz: edd697d7696e8e96783d4e02bfc37852df79abbacab5b992c1c6b8d0c95002763416caaf9e2bc2e6f51f1c98960612783cc182339e6b0956ce6ef95873cad675
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
0.4.0 (2014-05-22) ‘De Vorzon’
|
2
|
+
Big release with quite a few changes:
|
3
|
+
- (BACKWARDS INCOMPATIBILITY) Reorganise classes into submodules. This has
|
4
|
+
changed the name of pretty much every class in Compo.
|
5
|
+
- Null composites are now renamed to be Leaf composites, for consistency.
|
6
|
+
- Add branch#find_url, as a shortcut for invoking a UrlFinder.
|
7
|
+
- Add Compo::Branches::Constant, a Leaf branch containing a constant value.
|
8
|
+
|
1
9
|
0.3.1 (2014-05-21)
|
2
10
|
- Add UrlFinder class, for finding children inside a composite structure via
|
3
11
|
their URLs.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'compo/branches/branch'
|
2
|
+
require 'compo/composites'
|
3
|
+
|
4
|
+
module Compo
|
5
|
+
module Branches
|
6
|
+
# A simple implementation of a branch, whose children are stored in an Array
|
7
|
+
#
|
8
|
+
# An array branch is a composite object that may be moved into other
|
9
|
+
# composite objects. It stores its children as an Array, and the ID of each
|
10
|
+
# child is its current index in the array. Inserting and removing items
|
11
|
+
# into the branch may change the IDs of items with higher indices in the
|
12
|
+
# array.
|
13
|
+
class Array < Compo::Composites::Array
|
14
|
+
include Branch
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'compo/mixins'
|
2
|
+
require 'compo/finders'
|
3
|
+
|
4
|
+
module Compo
|
5
|
+
module Branches
|
6
|
+
# A movable, URL referenceable parent tracker
|
7
|
+
#
|
8
|
+
# A Branch represents a fully-featured part of a composite object. This
|
9
|
+
# abstract pattern is implemented concretely by Leaf (a Branch with no
|
10
|
+
# children), Array (a Branch with a list of numerically identified
|
11
|
+
# children), and Hash (a Branch with a hash of key-identified children).
|
12
|
+
module Branch
|
13
|
+
include Mixins::Movable
|
14
|
+
include Mixins::ParentTracker
|
15
|
+
include Mixins::UrlReferenceable
|
16
|
+
|
17
|
+
# Traverses this Branch and its children following a URL
|
18
|
+
#
|
19
|
+
# See Compo::Finders::Url for more information about what this means.
|
20
|
+
# This is a convenience wrapper over that method object, and is equivalent
|
21
|
+
# to 'Compo::Finders::Url.find(self, *args, &block)'.
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
# @example From this Branch, find the item at 'a/b/1'.
|
25
|
+
# branch.on_url('a/b/1') { |item| p item }
|
26
|
+
#
|
27
|
+
# @yieldparam [Object] The found resource.
|
28
|
+
#
|
29
|
+
# @return [Object] Whatever is returned by the block.
|
30
|
+
def find_url(*args, &block)
|
31
|
+
Compo::Finders::Url.find(self, *args, &block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'compo/branches/leaf'
|
2
|
+
|
3
|
+
module Compo
|
4
|
+
module Branches
|
5
|
+
# A Leaf containing a constant value
|
6
|
+
#
|
7
|
+
# The value can be retrieved using #value.
|
8
|
+
class Constant < Leaf
|
9
|
+
# Initialises the Constant
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
# @example Initialising a Constant with a given value.
|
13
|
+
# Constant.new(:value)
|
14
|
+
#
|
15
|
+
# @param value [Object] The value of the constant.
|
16
|
+
#
|
17
|
+
def initialize(value)
|
18
|
+
super()
|
19
|
+
@value = value
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the current value of this Constant
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
# @example Retrieving a Constant's value.
|
26
|
+
# const = Constant.new(:spoon)
|
27
|
+
# const.value
|
28
|
+
# #=> :spoon
|
29
|
+
#
|
30
|
+
# @return [Object] The Constant's internal value.
|
31
|
+
attr_reader :value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'compo/branches/branch'
|
2
|
+
require 'compo/composites'
|
3
|
+
|
4
|
+
module Compo
|
5
|
+
module Branches
|
6
|
+
# A simple implementation of a branch, whose children are stored in an Hash
|
7
|
+
#
|
8
|
+
# A hash branch is a composite object that may be moved into other composite
|
9
|
+
# objects. It stores its children as an Hash, and the ID of each child is
|
10
|
+
# its hash key. Inserting and removing items into the branch will not
|
11
|
+
# change the IDs of other items, but inserting with an existing key will
|
12
|
+
# remove the previous occupant.
|
13
|
+
class Hash < Compo::Composites::Hash
|
14
|
+
include Branch
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'compo/branches/branch'
|
2
|
+
require 'compo/composites'
|
3
|
+
|
4
|
+
module Compo
|
5
|
+
module Branches
|
6
|
+
# A simple implementation of a leaf node
|
7
|
+
#
|
8
|
+
# Leaves have no children, but can be moved to one. They implement the
|
9
|
+
# Composite API, but all additions and removals fail, and the Leaf always
|
10
|
+
# reports no children.
|
11
|
+
class Leaf < Compo::Composites::Leaf
|
12
|
+
include Branch
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'compo/branches/array'
|
2
|
+
require 'compo/branches/branch'
|
3
|
+
require 'compo/branches/hash'
|
4
|
+
require 'compo/branches/leaf'
|
5
|
+
require 'compo/branches/constant'
|
6
|
+
|
7
|
+
module Compo
|
8
|
+
# Module implementing the branch classes
|
9
|
+
#
|
10
|
+
# A branch is a fully-featured part of a Compo composite object. It tracks
|
11
|
+
# both children (if applicable) and its parent (if any), and supports a range
|
12
|
+
# of helper methods for traversing the composite tree.
|
13
|
+
module Branches
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'compo/composites/composite'
|
3
|
+
|
4
|
+
module Compo
|
5
|
+
module Composites
|
6
|
+
# Implementation of Composite that stores its children in an Array.
|
7
|
+
#
|
8
|
+
# IDs for items entering an Array must be numeric, and will change if
|
9
|
+
# an item with an ID less than the item in question is deleted or inserted.
|
10
|
+
# This means the ID function for objects in an Array may report
|
11
|
+
# different values at different times.
|
12
|
+
#
|
13
|
+
# Adding an object at an occupied ID moves the occupant and those at
|
14
|
+
# successive IDs up by one.
|
15
|
+
class Array
|
16
|
+
include Composite
|
17
|
+
extend Forwardable
|
18
|
+
|
19
|
+
# Initialises an array composite
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
# @example Initializes an array composite.
|
23
|
+
# comp = Compo::Composites::Array.new
|
24
|
+
def initialize
|
25
|
+
@children = []
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the array composite's children, as a Hash
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
# @example Gets the children of an empty array composite.
|
32
|
+
# comp.children
|
33
|
+
# #=> {}
|
34
|
+
# @example Gets the children of a populated array composite.
|
35
|
+
# comp.children
|
36
|
+
# #=> {0: :first, 1: :second}
|
37
|
+
#
|
38
|
+
# @return [Hash] The Hash mapping the IDs of children to their values.
|
39
|
+
def children
|
40
|
+
::Hash[(0...@children.size).zip(@children)]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def_delegator :@children, :delete, :remove!
|
46
|
+
def_delegator :@children, :delete_at, :remove_id!
|
47
|
+
|
48
|
+
# Inserts a child into the array composite with the given ID
|
49
|
+
#
|
50
|
+
# You probably want to use #add instead.
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
#
|
54
|
+
# @param id [Object] The ID under which the child is to be added.
|
55
|
+
# @param child [Object] The child to add to the array composite.
|
56
|
+
#
|
57
|
+
# @return [Object] The newly added child, or nil if the ID was invalid.
|
58
|
+
def add!(id, child)
|
59
|
+
valid_id?(id) ? do_insert(id, child) : nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Checks to see if the given ID is valid
|
63
|
+
#
|
64
|
+
# A valid ID for ArrayComposites is a number between 0 and the current
|
65
|
+
# size of the children list.
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
#
|
69
|
+
# @param id [Object] The candidate ID.
|
70
|
+
#
|
71
|
+
# @return [Boolean] True if the ID is valid; false if not.
|
72
|
+
def valid_id?(id)
|
73
|
+
id.is_a?(Numeric) && (0..@children.size).cover?(id)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Actually performs the insertion of an item into the array
|
77
|
+
#
|
78
|
+
# @api private
|
79
|
+
#
|
80
|
+
# @param id [Numeric] The index into the array at which the child is to
|
81
|
+
# be inserted.
|
82
|
+
# @param child [Object] The object to insert into the children array.
|
83
|
+
#
|
84
|
+
# @return [Object] The inserted child.
|
85
|
+
def do_insert(id, child)
|
86
|
+
@children.insert(id, child)
|
87
|
+
child
|
88
|
+
end
|
89
|
+
|
90
|
+
# Creates an ID function for the given child
|
91
|
+
#
|
92
|
+
# The returned proc is O(n), as it checks the child array at each call to
|
93
|
+
# find the current ID of the child.
|
94
|
+
#
|
95
|
+
# @api private
|
96
|
+
#
|
97
|
+
# @param child [Object] The child whose ID is to be returned by the proc.
|
98
|
+
#
|
99
|
+
# @return [Proc] A proc returning the child's ID.
|
100
|
+
def id_function(object)
|
101
|
+
proc { @children.index(object) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Compo
|
4
|
+
module Composites
|
5
|
+
# Mixin for objects that can contain other objects
|
6
|
+
#
|
7
|
+
# Objects implementing this interface should implement add!, remove! or
|
8
|
+
# remove_id!, and id_function.
|
9
|
+
#
|
10
|
+
# add! - Given a desired ID and child, adds the child to the children
|
11
|
+
# of this object; returns the child if successful, nil
|
12
|
+
# otherwise.
|
13
|
+
# remove! - Given a child, removes and returns it from the children; if
|
14
|
+
# not provided, this is implemented in terms of remove_id!.
|
15
|
+
# remove_id! - Given an ID, removes and returns the child with this ID from
|
16
|
+
# the children; if not provided, this is implemented in terms
|
17
|
+
# of remove!.
|
18
|
+
# children - Returns the children, as a Hash mapping from current IDs to
|
19
|
+
# their child values.
|
20
|
+
# id_function - Given a newly inserted child, returns a proc that will
|
21
|
+
# always return the child's current ID so long as it is part
|
22
|
+
# of the Composite.
|
23
|
+
module Composite
|
24
|
+
extend Forwardable
|
25
|
+
include Enumerable
|
26
|
+
|
27
|
+
# Adds a child to this Composite
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
# @example Adds a child with intended id 3.
|
31
|
+
# composite.add_child(3, leaf)
|
32
|
+
#
|
33
|
+
# @param id [Object] The intended ID of the child in this Composite.
|
34
|
+
# The actual ID may not be the same as this; consult the proc supplied
|
35
|
+
# to the child via #update_parent.
|
36
|
+
# @param child [Object] The child to add to this Composite.
|
37
|
+
#
|
38
|
+
# @return [Object] The added child if successful; nil otherwise.
|
39
|
+
def add(id, child)
|
40
|
+
add!(id, child).tap(&method(:assign_parent_to))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Removes a child from this Composite directly
|
44
|
+
#
|
45
|
+
# This method can fail (for example, if the child does not exist in the
|
46
|
+
# Composite).
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
# @example Removes a child.
|
50
|
+
# composite.remove(child)
|
51
|
+
#
|
52
|
+
# @param child [Object] The child to remove from this object.
|
53
|
+
#
|
54
|
+
# @return [Object] The removed child if successful; nil otherwise.
|
55
|
+
def remove(child)
|
56
|
+
remove!(child).tap(&method(:remove_parent_of))
|
57
|
+
end
|
58
|
+
|
59
|
+
# Removes a child from this Composite, given its ID
|
60
|
+
#
|
61
|
+
# This method can fail (for example, if the ID does not exist in the
|
62
|
+
# Composite).
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
# @example Removes the child with ID :foo.
|
66
|
+
# composite.remove_id(:foo)
|
67
|
+
#
|
68
|
+
# @param id The ID of the child to remove from this object.
|
69
|
+
#
|
70
|
+
# @return [Object] The removed child if successful; nil otherwise.
|
71
|
+
def remove_id(id)
|
72
|
+
remove_id!(id).tap(&method(:remove_parent_of))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Gets the child in this Composite with the given ID
|
76
|
+
#
|
77
|
+
# The ID is compared directly against the IDs of the children of this
|
78
|
+
# composite. To use a predicate to find an ID, use #get_child_such_that.
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
# @example Gets the child with ID :in, if children is {in: 3}.
|
82
|
+
# composite.get_child(:in)
|
83
|
+
# #=> 3
|
84
|
+
# @example Fails to get the child with ID :out, if children is {in: 3}.
|
85
|
+
# composite.get_child(:out)
|
86
|
+
# #=> nil
|
87
|
+
# @example Fails to get the child with ID '1', if children is {1 => 3}.
|
88
|
+
# composite.get_child('1')
|
89
|
+
# #=> nil
|
90
|
+
#
|
91
|
+
# @param id [Object] The ID of the child to get from this Composite.
|
92
|
+
#
|
93
|
+
# @return [Object] The child if successful; nil otherwise.
|
94
|
+
def get_child(id)
|
95
|
+
children[id]
|
96
|
+
end
|
97
|
+
|
98
|
+
# Gets the child in this Composite whose ID matches a given predicate
|
99
|
+
#
|
100
|
+
# If multiple children match this predicate, the result is the first child
|
101
|
+
# in the hash.
|
102
|
+
#
|
103
|
+
# @api public
|
104
|
+
# @example Gets the child with ID :in, if children is {in: 3}.
|
105
|
+
# composite.get_child_such_that { |x| x == :in }
|
106
|
+
# #=> 3
|
107
|
+
# @example Fails to get the child with ID :out, if children is {in: 3}.
|
108
|
+
# composite.get_child_such_that { |x| x == :out }
|
109
|
+
# #=> nil
|
110
|
+
# @example Get the child with an ID whose string form is '1', if children
|
111
|
+
# is {1 => 3}.
|
112
|
+
# composite.get_child_such_that { |x| x.to_s == '3' }
|
113
|
+
# #=> 3
|
114
|
+
#
|
115
|
+
# @yieldparam id [Object] An ID to check against the predicate.
|
116
|
+
#
|
117
|
+
# @return [Object] The child if successful; nil otherwise.
|
118
|
+
def get_child_such_that(&block)
|
119
|
+
child = children.each.find { |k, _| block.call(k) }
|
120
|
+
(_, value) = child unless child.nil?
|
121
|
+
value
|
122
|
+
end
|
123
|
+
|
124
|
+
def_delegator :children, :each
|
125
|
+
|
126
|
+
protected
|
127
|
+
|
128
|
+
# Assigns this object to a child as its parent
|
129
|
+
#
|
130
|
+
# This also updates its ID function to point to the child's ID under this
|
131
|
+
# parent.
|
132
|
+
#
|
133
|
+
# @api private
|
134
|
+
#
|
135
|
+
# @param child [Object] The child whose parent assignment is being set.
|
136
|
+
#
|
137
|
+
# @return [void]
|
138
|
+
def assign_parent_to(child)
|
139
|
+
child.update_parent(self, id_function(child)) unless child.nil?
|
140
|
+
end
|
141
|
+
|
142
|
+
# Removes a child's parent assignment
|
143
|
+
#
|
144
|
+
# This also clears its ID function.
|
145
|
+
#
|
146
|
+
# @api private
|
147
|
+
#
|
148
|
+
# @param child [Object] The child whose parent assignment is being set.
|
149
|
+
#
|
150
|
+
# @return [void]
|
151
|
+
def remove_parent_of(child)
|
152
|
+
Parentless.for(child)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Default implementation of #remove! in terms of #remove_id!
|
156
|
+
#
|
157
|
+
# Either this or #remove_id! must be overridden by the implementing class.
|
158
|
+
#
|
159
|
+
# @api private
|
160
|
+
#
|
161
|
+
# @param child [Object] The child to remove from this object.
|
162
|
+
#
|
163
|
+
# @return [void]
|
164
|
+
def remove!(child)
|
165
|
+
remove_id!(children.key(child))
|
166
|
+
end
|
167
|
+
|
168
|
+
# Default implementation of #remove_id! in terms of #remove!
|
169
|
+
#
|
170
|
+
# Either this or #remove! must be overridden by the implementing class.
|
171
|
+
#
|
172
|
+
# @api private
|
173
|
+
#
|
174
|
+
# @param id [Object] The current ID of the child to remove from this
|
175
|
+
# object.
|
176
|
+
#
|
177
|
+
# @return [void]
|
178
|
+
def remove_id!(id)
|
179
|
+
remove!(get_child(id))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'compo/composites/composite'
|
3
|
+
|
4
|
+
module Compo
|
5
|
+
module Composites
|
6
|
+
# Implementation of Composite that stores its children in a Hash.
|
7
|
+
#
|
8
|
+
# IDs for items entering a ListComposite may be any permissible hash.
|
9
|
+
#
|
10
|
+
# Adding an item at an occupied ID removes the occupant.
|
11
|
+
class Hash
|
12
|
+
include Composite
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
# Initialises a hash composite
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
# @example Initializes a hash composite.
|
19
|
+
# comp = Compo::Composites::Hash.new
|
20
|
+
def initialize
|
21
|
+
@children = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the hash composite's children, as a Hash
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
# @example Gets the children of an empty hash composite.
|
28
|
+
# comp.children
|
29
|
+
# #=> {}
|
30
|
+
# @example Gets the children of a populated hash composite.
|
31
|
+
# comp.children
|
32
|
+
# #=> {foo: 3, bar: 5}
|
33
|
+
#
|
34
|
+
# @return [Hash] The Hash mapping the IDs of children to their values.
|
35
|
+
attr_reader :children
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Inserts a child into the hash composite with the given ID
|
40
|
+
#
|
41
|
+
# You probably want to use #add instead.
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
#
|
45
|
+
# @param id [Object] The ID under which the child is to be added.
|
46
|
+
# @param child [Object] The child to add to the hash composite.
|
47
|
+
#
|
48
|
+
# @return [Object] The newly added child.
|
49
|
+
def add!(id, child)
|
50
|
+
remove_id(id)
|
51
|
+
@children[id] = child
|
52
|
+
end
|
53
|
+
|
54
|
+
def_delegator :@children, :delete, :remove_id!
|
55
|
+
|
56
|
+
# Creates an ID function for the given child
|
57
|
+
#
|
58
|
+
# The returned proc is O(1), as it stores the ID assigned to the child at
|
59
|
+
# calling time under the assumption that it will not change until removal.
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
#
|
63
|
+
# @param child [Object] The child whose ID is to be returned by the proc.
|
64
|
+
#
|
65
|
+
# @return [Proc] A proc returning the child's ID.
|
66
|
+
def id_function(child)
|
67
|
+
id = @children.key(child)
|
68
|
+
proc { id }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'compo/composites/composite'
|
2
|
+
|
3
|
+
module Compo
|
4
|
+
module Composites
|
5
|
+
# A Composite that cannot have children
|
6
|
+
#
|
7
|
+
# Add/remove operations on a leaf composite always fail, and #children
|
8
|
+
# always returns the empty hash.
|
9
|
+
#
|
10
|
+
# This is useful for leaf classes that still need to expose the composite
|
11
|
+
# API.
|
12
|
+
class Leaf
|
13
|
+
include Composite
|
14
|
+
|
15
|
+
# Returns the empty hash
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
# @example Gets the children
|
19
|
+
# comp.children
|
20
|
+
# #=> {}
|
21
|
+
#
|
22
|
+
# @return [Hash] The empty hash.
|
23
|
+
def children
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Fails to add a child into the leaf
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
# @param id [Object] Ignored.
|
34
|
+
# @param child [Object] Ignored.
|
35
|
+
#
|
36
|
+
# @return [nil]
|
37
|
+
def add!(_, _)
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Fails to remove the given child
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
#
|
45
|
+
# @param child [Object] Ignored.
|
46
|
+
#
|
47
|
+
# @return [nil]
|
48
|
+
def remove!(_)
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# Fails to remove the child with the given ID
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
#
|
56
|
+
# @param id [Object] Ignored.
|
57
|
+
#
|
58
|
+
# @return [nil]
|
59
|
+
def remove_id!(_)
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|