compo 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|