compo 0.3.0 → 0.3.1
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 +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:
|