compo 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +5 -0
- data/README.md +12 -6
- data/lib/compo.rb +3 -0
- data/lib/compo/composite.rb +32 -0
- data/lib/compo/parent_tracker.rb +10 -0
- data/lib/compo/url_finder.rb +164 -0
- data/lib/compo/version.rb +1 -1
- data/spec/branch_shared_examples.rb +20 -2
- data/spec/branch_spec.rb +12 -0
- data/spec/parent_tracker_spec.rb +3 -0
- data/spec/url_finder_spec.rb +129 -0
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 463952c33e420e5ab401ec9774208262b4606ebc
|
4
|
+
data.tar.gz: 59ff0efef46f9db2fd9fdf72c463fccb46b18b96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ead1e453e9ba923f8dcb12b2c9ec211d8d8946323557175eb82c0236939afc42314bc83c139f4e4076b1d3c0f4850910afcad3a29ed4b67ef9309e209eb97dbc
|
7
|
+
data.tar.gz: 890b61d951ad12e56aa2f329506f803dbde105c8541afd2332fb520f973a745fbacd845a7b1f213f69230cfa51e4c326c9704427561a78c754fd6ed69ee1d14c
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
0.3.1 (2014-05-21)
|
2
|
+
- Add UrlFinder class, for finding children inside a composite structure via
|
3
|
+
their URLs.
|
4
|
+
- 100% YARD, LOC and Rubocop coverage.
|
5
|
+
|
1
6
|
0.3.0 (2014-05-21)
|
2
7
|
- Require bundler 1.6.
|
3
8
|
- Remove some unnecessary checks for nil: Parentless should be used instead.
|
data/README.md
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
**Compo** is a library providing mixins and base classes for setting up
|
4
4
|
composite objects.
|
5
5
|
|
6
|
-
It
|
7
|
-
|
8
|
-
such as
|
6
|
+
It's similar to the Gang of Four Composite pattern, but in Compo
|
7
|
+
children are identified in their parents by an *ID*,
|
8
|
+
such as an index or hash key, that the child is aware of at all times.
|
9
9
|
|
10
|
-
Compo was designed for
|
10
|
+
Compo was designed for models whose composite
|
11
11
|
structure can be expressed as URLs made from their recursive ID trails.
|
12
12
|
|
13
13
|
## Installation
|
@@ -33,6 +33,8 @@ Compo consists of several classes and mixins that implement various parts of the
|
|
33
33
|
- **Composite**, which specifies the #add/#remove/#remove_id/#get_child API on top of an implementation;
|
34
34
|
- **Movable**, which creates a #move_to method that simplifies the act of moving a child between Composites;
|
35
35
|
- **ParentTracker**, which implements keeping track of a child's parent and the child end of #add/#remove;
|
36
|
+
- **URLReferenceable**, which allows the current position of an object in a hierarchy of composites to be retrieved as an URL-style reference;
|
37
|
+
- **Branch**, which is simply a **Moveable** **URLReferenceable** **ParentTracker**.
|
36
38
|
|
37
39
|
### Composite implementation classes
|
38
40
|
|
@@ -44,9 +46,13 @@ These implement the methods needed for **Composite** to work, but don't implemen
|
|
44
46
|
|
45
47
|
### Simple leaf and node classes
|
46
48
|
|
47
|
-
These include **
|
49
|
+
These include **Branch**, and thus can be moved around, added to and removed from composites, and track their current parents and IDs.
|
48
50
|
|
49
|
-
- **Leaf**, which is based on NullComposite and is intended for objects that don't have children but can be placed in other Composites
|
51
|
+
- **Leaf**, which is based on NullComposite and is intended for objects that don't have children but can be placed in other Composites;
|
52
|
+
- **ArrayBranch**, which is based on ArrayComposite;
|
53
|
+
- **HashBranch**, which is based on HashComposite.
|
54
|
+
|
55
|
+
Generally, you'll only need to use these classes (use **Leaf** when creating objects that can be part of other objects but not have children themselves, **ArrayBranch** when an object has a list of ordered children *whose ordering changes as more children are added and deleted*, and **HashBranch** when it has a collection of children with arbitrary IDs).
|
50
56
|
|
51
57
|
## Contributing
|
52
58
|
|
data/lib/compo.rb
CHANGED
data/lib/compo/composite.rb
CHANGED
@@ -73,6 +73,9 @@ module Compo
|
|
73
73
|
|
74
74
|
# Gets the child in this Composite with the given ID
|
75
75
|
#
|
76
|
+
# The ID is compared directly against the IDs of the children of this
|
77
|
+
# composite. To use a predicate to find an ID, use #get_child_such_that.
|
78
|
+
#
|
76
79
|
# @api public
|
77
80
|
# @example Gets the child with ID :in, if children is {in: 3}.
|
78
81
|
# composite.get_child(:in)
|
@@ -80,6 +83,9 @@ module Compo
|
|
80
83
|
# @example Fails to get the child with ID :out, if children is {in: 3}.
|
81
84
|
# composite.get_child(:out)
|
82
85
|
# #=> nil
|
86
|
+
# @example Fails to get the child with ID '1', if children is {1 => 3}.
|
87
|
+
# composite.get_child('1')
|
88
|
+
# #=> nil
|
83
89
|
#
|
84
90
|
# @param id [Object] The ID of the child to get from this Composite.
|
85
91
|
#
|
@@ -88,6 +94,32 @@ module Compo
|
|
88
94
|
children[id]
|
89
95
|
end
|
90
96
|
|
97
|
+
# Gets the child in this Composite whose ID matches a given predicate
|
98
|
+
#
|
99
|
+
# If multiple children match this predicate, the result is the first child
|
100
|
+
# in the hash.
|
101
|
+
#
|
102
|
+
# @api public
|
103
|
+
# @example Gets the child with ID :in, if children is {in: 3}.
|
104
|
+
# composite.get_child_such_that { |x| x == :in }
|
105
|
+
# #=> 3
|
106
|
+
# @example Fails to get the child with ID :out, if children is {in: 3}.
|
107
|
+
# composite.get_child_such_that { |x| x == :out }
|
108
|
+
# #=> nil
|
109
|
+
# @example Get the child with an ID whose string form is '1', if children
|
110
|
+
# is {1 => 3}.
|
111
|
+
# composite.get_child_such_that { |x| x.to_s == '3' }
|
112
|
+
# #=> 3
|
113
|
+
#
|
114
|
+
# @yieldparam id [Object] An ID to check against the predicate.
|
115
|
+
#
|
116
|
+
# @return [Object] The child if successful; nil otherwise.
|
117
|
+
def get_child_such_that(&block)
|
118
|
+
child = children.each.find { |k, _| block.call(k) }
|
119
|
+
(_, value) = child unless child.nil?
|
120
|
+
value
|
121
|
+
end
|
122
|
+
|
91
123
|
def_delegator :children, :each
|
92
124
|
|
93
125
|
protected
|
data/lib/compo/parent_tracker.rb
CHANGED
@@ -10,6 +10,16 @@ module Compo
|
|
10
10
|
module ParentTracker
|
11
11
|
extend Forwardable
|
12
12
|
|
13
|
+
# Initialises the ParentTracker
|
14
|
+
#
|
15
|
+
# This constructor sets the tracker up so it initially has an instance of
|
16
|
+
# Parentless as its 'parent'.
|
17
|
+
#
|
18
|
+
# @api semipublic
|
19
|
+
# @example Creates a new ParentTracker.
|
20
|
+
# ParentTracker.new
|
21
|
+
#
|
22
|
+
# @return [Void]
|
13
23
|
def initialize
|
14
24
|
super()
|
15
25
|
remove_parent
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module Compo
|
2
|
+
# An 'UrlFinder' finds an object in a composite tree via its URL
|
3
|
+
#
|
4
|
+
# It is a method object that implements only the finding of a specific URL.
|
5
|
+
# UrlFinders are *not* thread-safe.
|
6
|
+
class UrlFinder
|
7
|
+
# Initialises a UrlFinder
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
# @example Initialises an UrlFinder with default missing resource handling.
|
11
|
+
# UrlFinder.new(composite, 'a/b/c')
|
12
|
+
# @example Initialises an UrlFinder returning a default value.
|
13
|
+
# UrlFinder.new(composite, 'a/b/c', missing_proc=->(_) { :default })
|
14
|
+
#
|
15
|
+
# @param root [Composite] A composite object serving as the root of the
|
16
|
+
# search tree, and the URL.
|
17
|
+
#
|
18
|
+
# @param url [String] A partial URL that follows this model object's URL
|
19
|
+
# to form the URL of the resource to locate. Can be nil, in which case
|
20
|
+
# this object is returned.
|
21
|
+
#
|
22
|
+
# @param missing_proc [Proc] A proc to call, with the requested URL, if the
|
23
|
+
# resource could not be found. If nil (the default), this raises a string
|
24
|
+
# exception.
|
25
|
+
def initialize(root, url, missing_proc: nil)
|
26
|
+
@root = root
|
27
|
+
@url = url
|
28
|
+
@missing_proc = missing_proc || method(:default_missing_proc)
|
29
|
+
|
30
|
+
reset
|
31
|
+
end
|
32
|
+
|
33
|
+
# Finds the model object at a URL, given a model root
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
# @example Finds a URL with default missing resource handling.
|
37
|
+
# UrlFinder.find(composite, 'a/b/c') { |item| p item }
|
38
|
+
#
|
39
|
+
# @param (see #initialize)
|
40
|
+
#
|
41
|
+
# @yieldparam (see #run)
|
42
|
+
#
|
43
|
+
# @return [Object] The return value of the block.
|
44
|
+
def self.find(*args, &block)
|
45
|
+
new(*args).run(&block)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Attempts to find a child resource with the given partial URL
|
49
|
+
#
|
50
|
+
# If the resource is found, it will be yielded to the attached block;
|
51
|
+
# otherwise, an exception will be raised.
|
52
|
+
#
|
53
|
+
# @api public
|
54
|
+
# @example Runs an UrlFinder, returning the item unchanged.
|
55
|
+
# finder.run { |item| item }
|
56
|
+
# #=> item
|
57
|
+
#
|
58
|
+
# @yieldparam resource [ModelObject] The resource found.
|
59
|
+
# @yieldparam args [Array] The splat from above.
|
60
|
+
#
|
61
|
+
# @return [Object] The return value of the block.
|
62
|
+
def run
|
63
|
+
# We're traversing down the URL by repeatedly splitting it into its
|
64
|
+
# head (part before the next /) and tail (part after). While we still
|
65
|
+
# have a tail, then the URL still needs walking down.
|
66
|
+
reset
|
67
|
+
descend until hit_end_of_url?
|
68
|
+
yield @resource
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Performs a descending step in the URL finder
|
74
|
+
#
|
75
|
+
# This tries to move down a level of the URL hierarchy, fetches the
|
76
|
+
# resource at that level, and fails according to @missing_proc if there is
|
77
|
+
# no such resource.
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
#
|
81
|
+
# @return [Void]
|
82
|
+
def descend
|
83
|
+
descend_url
|
84
|
+
next_resource
|
85
|
+
fail_with_no_resource if @resource.nil?
|
86
|
+
end
|
87
|
+
|
88
|
+
# Seeks to the next resource pointed at by @next_id
|
89
|
+
#
|
90
|
+
# @api private
|
91
|
+
#
|
92
|
+
# @return [Void]
|
93
|
+
def next_resource
|
94
|
+
@resource = @resource.get_child_such_that { |id| id.to_s == @next_id }
|
95
|
+
end
|
96
|
+
|
97
|
+
# Fails, using @missing_proc, due to a missing resource
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
#
|
101
|
+
# @return [Void]
|
102
|
+
def fail_with_no_resource
|
103
|
+
# If the proc returns a value instead of raising an error, then set
|
104
|
+
# things up so that value is yielded in place of the missing resource.
|
105
|
+
@tail = nil
|
106
|
+
@resource = @missing_proc.call(@url)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Default value for @missing_proc
|
110
|
+
#
|
111
|
+
# @api private
|
112
|
+
#
|
113
|
+
# @param url [String] The URL whose finding failed.
|
114
|
+
#
|
115
|
+
# @return [Void]
|
116
|
+
def default_missing_proc(url)
|
117
|
+
fail("Could not find resource: #{url}")
|
118
|
+
end
|
119
|
+
|
120
|
+
# Decides whether we have reached the end of the URL
|
121
|
+
#
|
122
|
+
# @api private
|
123
|
+
#
|
124
|
+
# @return [Boolean] Whether we have hit the end of the URL.
|
125
|
+
def hit_end_of_url?
|
126
|
+
@tail.nil? || @tail.empty?
|
127
|
+
end
|
128
|
+
|
129
|
+
# Splits the tail on the next URL level
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
#
|
133
|
+
# @return [Void]
|
134
|
+
def descend_url
|
135
|
+
@next_id, @tail = @tail.split('/', 2)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Resets this UrlFinder so it can be used again
|
139
|
+
#
|
140
|
+
# @api private
|
141
|
+
#
|
142
|
+
# @return [Void]
|
143
|
+
def reset
|
144
|
+
@next_id, @tail = nil, trimmed_url
|
145
|
+
@resource = @root
|
146
|
+
end
|
147
|
+
|
148
|
+
# Removes any leading or trailing slash from the URL, returning the result
|
149
|
+
#
|
150
|
+
# This only removes one leading or trailing slash. Thus, '///' will be
|
151
|
+
# returned as '/'.
|
152
|
+
#
|
153
|
+
# @api private
|
154
|
+
#
|
155
|
+
# @return [String] The URL with no trailing or leading slash.
|
156
|
+
def trimmed_url
|
157
|
+
first, last = 0, @url.length
|
158
|
+
first += 1 if @url.start_with?('/')
|
159
|
+
last -= 1 if @url.end_with?('/')
|
160
|
+
|
161
|
+
@url[first...last]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/lib/compo/version.rb
CHANGED
@@ -16,12 +16,12 @@ shared_examples 'a branch' do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
describe '#url' do
|
19
|
-
context 'when the
|
19
|
+
context 'when the Branch has no parent' do
|
20
20
|
it 'returns the empty string' do
|
21
21
|
expect(subject.url).to eq('')
|
22
22
|
end
|
23
23
|
end
|
24
|
-
context 'when the
|
24
|
+
context 'when the Branch is the child of a root' do
|
25
25
|
let(:parent) { Compo::HashBranch.new }
|
26
26
|
before(:each) { subject.move_to(parent, :id) }
|
27
27
|
|
@@ -30,4 +30,22 @@ shared_examples 'a branch' do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
describe '#move_to' do
|
35
|
+
context 'when the Branch has a parent' do
|
36
|
+
context 'when the new parent is nil' do
|
37
|
+
let(:parent) { Compo::HashBranch.new }
|
38
|
+
before(:each) { subject.move_to(parent, :id) }
|
39
|
+
|
40
|
+
it 'loses its previous parent' do
|
41
|
+
expect(subject.move_to(nil, :id).parent).to be_a(Compo::Parentless)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'is no longer a child of its parent' do
|
45
|
+
subject.move_to(nil, :id)
|
46
|
+
expect(parent.children).to_not include(subject)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
33
51
|
end
|
data/spec/branch_spec.rb
ADDED
data/spec/parent_tracker_spec.rb
CHANGED
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compo'
|
3
|
+
|
4
|
+
describe Compo::UrlFinder do
|
5
|
+
subject { Compo::UrlFinder }
|
6
|
+
describe '.find' do
|
7
|
+
let(:target) { Compo::Leaf.new }
|
8
|
+
|
9
|
+
let(:root) do
|
10
|
+
s = Compo::HashBranch.new
|
11
|
+
a = Compo::HashBranch.new
|
12
|
+
b = Compo::ArrayBranch.new
|
13
|
+
d = Compo::Leaf.new
|
14
|
+
e = Compo::Leaf.new
|
15
|
+
zero = Compo::Leaf.new
|
16
|
+
|
17
|
+
s.add('a', a)
|
18
|
+
a.add('b', b)
|
19
|
+
b.add(0, zero)
|
20
|
+
b.add(1, target)
|
21
|
+
s.add('d', d)
|
22
|
+
a.add('e', e)
|
23
|
+
s
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when given a nil root' do
|
27
|
+
specify { expect { |b| subject.find(nil, 'a/b/1', &b) }.to raise_error }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when given a nil URL' do
|
31
|
+
specify { expect { |b| subject.find(root, nil, &b) }.to raise_error }
|
32
|
+
end
|
33
|
+
|
34
|
+
shared_examples 'a successful finding' do
|
35
|
+
it 'returns the correct resource' do
|
36
|
+
expect { |b| subject.find(root, url, &b) }.to yield_with_args(target)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
shared_examples 'an unsuccessful finding' do
|
41
|
+
specify do
|
42
|
+
expect { |b| subject.find(root, url, &b) }.to raise_error(
|
43
|
+
"Could not find resource: #{url}"
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
shared_examples 'an unsuccessful finding with custom error' do
|
49
|
+
specify do
|
50
|
+
mp = ->(_) { :a }
|
51
|
+
expect { |b| subject.find(root, url, missing_proc: mp, &b) }
|
52
|
+
.to yield_with_args(:a)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when given a correct root but incorrect URL' do
|
57
|
+
context 'using the default missing resource handler' do
|
58
|
+
context 'when the URL has a leading slash' do
|
59
|
+
it_behaves_like 'an unsuccessful finding' do
|
60
|
+
let(:url) { '/a/z' }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
context 'when the URL has a trailing slash' do
|
64
|
+
it_behaves_like 'an unsuccessful finding' do
|
65
|
+
let(:url) { 'a/z/' }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
context 'when the URL has a leading and trailing slash' do
|
69
|
+
it_behaves_like 'an unsuccessful finding' do
|
70
|
+
let(:url) { '/a/z/' }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
context 'when the URL has neither leading nor trailing slash' do
|
74
|
+
it_behaves_like 'an unsuccessful finding' do
|
75
|
+
let(:url) { 'a/z' }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'using a custom error handler' do
|
81
|
+
context 'when the URL has a leading slash' do
|
82
|
+
it_behaves_like 'an unsuccessful finding with custom error' do
|
83
|
+
let(:url) { '/d/e/d' }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
context 'when the URL has a trailing slash' do
|
87
|
+
it_behaves_like 'an unsuccessful finding with custom error' do
|
88
|
+
let(:url) { 'd/e/d/' }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
context 'when the URL has a leading and trailing slash' do
|
92
|
+
it_behaves_like 'an unsuccessful finding with custom error' do
|
93
|
+
let(:url) { '/d/e/d/' }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
context 'when the URL has neither leading nor trailing slash' do
|
97
|
+
it_behaves_like 'an unsuccessful finding with custom error' do
|
98
|
+
let(:url) { 'd/e/d' }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when given a correct root and URL' do
|
105
|
+
context 'when the URL leads to a resource' do
|
106
|
+
context 'when the URL has a leading slash' do
|
107
|
+
it_behaves_like 'a successful finding' do
|
108
|
+
let(:url) { '/a/b/1' }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
context 'when the URL has a trailing slash' do
|
112
|
+
it_behaves_like 'a successful finding' do
|
113
|
+
let(:url) { 'a/b/1/' }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
context 'when the URL has a leading and trailing slash' do
|
117
|
+
it_behaves_like 'a successful finding' do
|
118
|
+
let(:url) { '/a/b/1/' }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
context 'when the URL has neither leading nor trailing slash' do
|
122
|
+
it_behaves_like 'a successful finding' do
|
123
|
+
let(:url) { 'a/b/1' }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: compo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Windsor
|
@@ -151,12 +151,14 @@ files:
|
|
151
151
|
- lib/compo/null_composite.rb
|
152
152
|
- lib/compo/parent_tracker.rb
|
153
153
|
- lib/compo/parentless.rb
|
154
|
+
- lib/compo/url_finder.rb
|
154
155
|
- lib/compo/url_referenceable.rb
|
155
156
|
- lib/compo/version.rb
|
156
157
|
- spec/array_branch_spec.rb
|
157
158
|
- spec/array_composite_shared_examples.rb
|
158
159
|
- spec/array_composite_spec.rb
|
159
160
|
- spec/branch_shared_examples.rb
|
161
|
+
- spec/branch_spec.rb
|
160
162
|
- spec/composite_shared_examples.rb
|
161
163
|
- spec/composite_spec.rb
|
162
164
|
- spec/hash_branch_spec.rb
|
@@ -170,6 +172,7 @@ files:
|
|
170
172
|
- spec/parent_tracker_spec.rb
|
171
173
|
- spec/parentless_spec.rb
|
172
174
|
- spec/spec_helper.rb
|
175
|
+
- spec/url_finder_spec.rb
|
173
176
|
- spec/url_referenceable_shared_examples.rb
|
174
177
|
- spec/url_referenceable_spec.rb
|
175
178
|
homepage: http://github.com/CaptainHayashi/compo
|
@@ -201,6 +204,7 @@ test_files:
|
|
201
204
|
- spec/array_composite_shared_examples.rb
|
202
205
|
- spec/array_composite_spec.rb
|
203
206
|
- spec/branch_shared_examples.rb
|
207
|
+
- spec/branch_spec.rb
|
204
208
|
- spec/composite_shared_examples.rb
|
205
209
|
- spec/composite_spec.rb
|
206
210
|
- spec/hash_branch_spec.rb
|
@@ -214,6 +218,7 @@ test_files:
|
|
214
218
|
- spec/parent_tracker_spec.rb
|
215
219
|
- spec/parentless_spec.rb
|
216
220
|
- spec/spec_helper.rb
|
221
|
+
- spec/url_finder_spec.rb
|
217
222
|
- spec/url_referenceable_shared_examples.rb
|
218
223
|
- spec/url_referenceable_spec.rb
|
219
224
|
has_rdoc:
|