hexp 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/Changelog.md +10 -0
- data/README.md +1 -1
- data/Rakefile +2 -1
- data/hexp.gemspec +0 -1
- data/lib/hexp.rb +1 -1
- data/lib/hexp/css_selector.rb +24 -1
- data/lib/hexp/list.rb +5 -3
- data/lib/hexp/mutable_tree_walk.rb +79 -0
- data/lib/hexp/node.rb +13 -3
- data/lib/hexp/node/attributes.rb +1 -1
- data/lib/hexp/node/css_selection.rb +17 -53
- data/lib/hexp/node/normalize.rb +12 -5
- data/lib/hexp/text_node.rb +0 -2
- data/lib/hexp/version.rb +1 -1
- data/spec/unit/hexp/mutable_tree_walk_spec.rb +72 -0
- data/spec/unit/hexp/node/css_selection_spec.rb +1 -1
- metadata +5 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45fe82cfc464b888c41d8b632a929f6074d9b1cb
|
4
|
+
data.tar.gz: 9a015de7db34bd56cadf8304a940d51fea9f6d9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef380c391229dcb9716d9472882714ded77f5c3e0169f8ff98312a5e23bd1b61e3caed513f0e2c561e86b9e399b94ee88d0fbd7606f1ee83b353884199cff596
|
7
|
+
data.tar.gz: 29570e22c84b840bd04429ca27f5dc9535e3e4b080007ffda9e80f9472b61ae476ca1a4a036600c8db6f6cd9921a2be0cd44dc8c394505b7a5642874b6148454
|
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
[full diff](http://github.com/plexus/hexp/compare/v0.4.2...master)
|
4
4
|
|
5
|
+
### v0.4.3
|
6
|
+
|
7
|
+
Performance improvements
|
8
|
+
|
9
|
+
* Introduce MutableTreeWalk to speed up css selection
|
10
|
+
* Drop Adamantium. This means we have less of a guarantee of deep
|
11
|
+
immutability, but it does speed things up
|
12
|
+
* Prevent type coercion from happening if inputs are already valid
|
13
|
+
* Raise an exception when a node's tag is not a Symbol
|
14
|
+
|
5
15
|
### v0.4.2
|
6
16
|
|
7
17
|
* Added Hexp::List#append
|
data/README.md
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
|
13
13
|
# Hexp
|
14
14
|
|
15
|
-
**Hexp** (pronounced [ˈɦækspi:]) is a DOM API for Ruby. It lets you treat HTML in your applications as objects, instead of strings. It is a standalone, framework independent library. You can use it to build full web pages, or to clean up your helpers and presenters.
|
15
|
+
**Hexp** (pronounced [ˈɦækspi:]) is a DOM API for Ruby. It lets you treat HTML in your applications as objects, instead of strings. It is a standalone, framework independent library. You can use it to build full web pages, or just to clean up your helpers and presenters.
|
16
16
|
|
17
17
|
## Fundamentals
|
18
18
|
|
data/Rakefile
CHANGED
@@ -48,6 +48,7 @@ task :default => :mutant
|
|
48
48
|
|
49
49
|
task :mutant do
|
50
50
|
pattern = ENV.fetch('PATTERN', 'Hexp*')
|
51
|
-
|
51
|
+
opts = ENV.fetch('MUTANT_OPTS', '').split(' ')
|
52
|
+
result = Mutant::CLI.run(%w[-Ilib -rhexp --use rspec --score 100] + opts + [pattern])
|
52
53
|
fail unless result == Mutant::CLI::EXIT_SUCCESS
|
53
54
|
end
|
data/hexp.gemspec
CHANGED
@@ -19,7 +19,6 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.add_runtime_dependency 'sass', '~> 3.2.19'
|
21
21
|
gem.add_runtime_dependency 'nokogiri', '~> 1.6'
|
22
|
-
gem.add_runtime_dependency 'adamantium', '~> 0.2'
|
23
22
|
gem.add_runtime_dependency 'equalizer', '~> 0.0'
|
24
23
|
gem.add_runtime_dependency 'concord', '~> 0.0'
|
25
24
|
|
data/lib/hexp.rb
CHANGED
@@ -4,7 +4,6 @@ require 'pathname'
|
|
4
4
|
|
5
5
|
require 'nokogiri'
|
6
6
|
require 'sass'
|
7
|
-
require 'adamantium'
|
8
7
|
require 'equalizer'
|
9
8
|
require 'concord'
|
10
9
|
|
@@ -126,3 +125,4 @@ require 'hexp/h'
|
|
126
125
|
|
127
126
|
require 'hexp/builder'
|
128
127
|
require 'hexp/unparser'
|
128
|
+
require 'hexp/mutable_tree_walk'
|
data/lib/hexp/css_selector.rb
CHANGED
@@ -4,7 +4,6 @@ module Hexp
|
|
4
4
|
#
|
5
5
|
module Members
|
6
6
|
include Equalizer.new(:members)
|
7
|
-
include Adamantium
|
8
7
|
|
9
8
|
extend Forwardable
|
10
9
|
def_delegator :@members, :empty?
|
@@ -106,6 +105,12 @@ module Hexp
|
|
106
105
|
sequence.head_matches?(element)
|
107
106
|
end
|
108
107
|
end
|
108
|
+
|
109
|
+
def matches_path?(path)
|
110
|
+
members.any? do |sequence|
|
111
|
+
sequence.matches_path?(path)
|
112
|
+
end
|
113
|
+
end
|
109
114
|
end
|
110
115
|
|
111
116
|
# A single CSS sequence like 'div span .foo'
|
@@ -124,6 +129,24 @@ module Hexp
|
|
124
129
|
members.first.matches?(element)
|
125
130
|
end
|
126
131
|
|
132
|
+
# Warning: Highly optimized cryptic code
|
133
|
+
def matches_path?(path)
|
134
|
+
return false if path.length < members.length
|
135
|
+
return false unless members.last.matches?(path.last)
|
136
|
+
|
137
|
+
path_idx = path.length - 2
|
138
|
+
mem_idx = members.length - 2
|
139
|
+
|
140
|
+
until path_idx < mem_idx || mem_idx == -1
|
141
|
+
if members[mem_idx].matches?(path[path_idx])
|
142
|
+
mem_idx -= 1
|
143
|
+
end
|
144
|
+
path_idx -= 1
|
145
|
+
end
|
146
|
+
|
147
|
+
mem_idx == -1
|
148
|
+
end
|
149
|
+
|
127
150
|
# Drop the first element of this Sequence
|
128
151
|
#
|
129
152
|
# This returns a new Sequence, with one member less.
|
data/lib/hexp/list.rb
CHANGED
@@ -2,8 +2,6 @@ module Hexp
|
|
2
2
|
# A list of nodes
|
3
3
|
#
|
4
4
|
class List < DelegateClass(Array)
|
5
|
-
include Adamantium
|
6
|
-
|
7
5
|
# Create new Hexp::List
|
8
6
|
#
|
9
7
|
# @example
|
@@ -14,7 +12,11 @@ module Hexp
|
|
14
12
|
#
|
15
13
|
# @api public
|
16
14
|
def initialize(nodes)
|
17
|
-
|
15
|
+
if nodes.instance_of?(List)
|
16
|
+
super(nodes.__getobj__).freeze
|
17
|
+
else
|
18
|
+
super nodes.to_ary.map(&Node::Normalize.method(:coerce_node)).freeze
|
19
|
+
end
|
18
20
|
end
|
19
21
|
|
20
22
|
# Convenience constructor
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Hexp
|
2
|
+
class MutableTreeWalk
|
3
|
+
attr_reader :root, :path, :result
|
4
|
+
|
5
|
+
def initialize(root)
|
6
|
+
@root = root
|
7
|
+
@path = [root]
|
8
|
+
@replacements = [{}]
|
9
|
+
@result = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def next!
|
13
|
+
return if end?
|
14
|
+
if current.children.any?
|
15
|
+
@path << current.children.first
|
16
|
+
@replacements << {}
|
17
|
+
elsif @path.length == 1
|
18
|
+
@result = @path.pop
|
19
|
+
else
|
20
|
+
backtrack_and_right!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def backtrack_and_right!
|
25
|
+
while at_rightmost_child?
|
26
|
+
@path.pop
|
27
|
+
handle_replacements!
|
28
|
+
if @path.length == 1 #back at start, we're done
|
29
|
+
@result = @path.pop
|
30
|
+
return
|
31
|
+
end
|
32
|
+
end
|
33
|
+
go_right!
|
34
|
+
end
|
35
|
+
|
36
|
+
def replace!(val)
|
37
|
+
@replacements.last[current_idx] = val
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_replacements!
|
41
|
+
replacements = @replacements.pop
|
42
|
+
return if replacements.empty?
|
43
|
+
new_children = [*current.children]
|
44
|
+
replacements.each do |idx, val|
|
45
|
+
new_children[idx..idx] = val
|
46
|
+
end
|
47
|
+
new_node = current.set_children(new_children)
|
48
|
+
if @path.length == 1
|
49
|
+
@path = [new_node]
|
50
|
+
else
|
51
|
+
@replacements.last[current_idx] = new_node
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def at_rightmost_child?
|
56
|
+
current.equal? parent.children.last
|
57
|
+
end
|
58
|
+
|
59
|
+
def go_right!
|
60
|
+
@path[-1] = parent.children[current_idx + 1]
|
61
|
+
end
|
62
|
+
|
63
|
+
def current_idx
|
64
|
+
parent.children.find_index { |ch| current.equal?(ch) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def parent
|
68
|
+
@path[-2]
|
69
|
+
end
|
70
|
+
|
71
|
+
def current
|
72
|
+
@path.last
|
73
|
+
end
|
74
|
+
|
75
|
+
def end?
|
76
|
+
@path.empty?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/hexp/node.rb
CHANGED
@@ -53,14 +53,12 @@ module Hexp
|
|
53
53
|
#
|
54
54
|
class Node
|
55
55
|
include Concord::Public.new(:tag, :attributes, :children)
|
56
|
-
include Adamantium
|
57
56
|
extend Forwardable
|
58
57
|
|
59
58
|
include Hexp::Node::Attributes
|
60
59
|
include Hexp::Node::Children
|
61
60
|
|
62
61
|
alias attrs attributes
|
63
|
-
memoize :class_list
|
64
62
|
|
65
63
|
# The HTML tag of this node
|
66
64
|
#
|
@@ -125,7 +123,19 @@ module Hexp
|
|
125
123
|
# @api public
|
126
124
|
#
|
127
125
|
def initialize(*args)
|
128
|
-
|
126
|
+
tag_ok = args[0].instance_of?(Symbol)
|
127
|
+
raise "The tag of node should be a Symbol" unless tag_ok
|
128
|
+
|
129
|
+
attrs_ok = args[1].instance_of?(Hash) &&
|
130
|
+
args[1].all? {|k,v| k.instance_of?(String) && v.instance_of?(String) }
|
131
|
+
|
132
|
+
if attrs_ok && args[2].instance_of?(List)
|
133
|
+
super(args[0], args[1], args[2])
|
134
|
+
elsif attrs_ok && args[2].instance_of?(Array)
|
135
|
+
super(args[0], args[1], List.new(args[2]))
|
136
|
+
else
|
137
|
+
super(*Normalize.new(args).call)
|
138
|
+
end.freeze
|
129
139
|
end
|
130
140
|
|
131
141
|
# Standard hexp coercion protocol, return self
|
data/lib/hexp/node/attributes.rb
CHANGED
@@ -73,10 +73,15 @@ module Hexp
|
|
73
73
|
def each(&block)
|
74
74
|
return to_enum(:each) unless block_given?
|
75
75
|
|
76
|
-
@node
|
77
|
-
|
76
|
+
walk = MutableTreeWalk.new(@node)
|
77
|
+
|
78
|
+
until walk.end?
|
79
|
+
if comma_sequence.matches_path?(walk.path)
|
80
|
+
yield walk.current
|
81
|
+
end
|
82
|
+
walk.next!
|
78
83
|
end
|
79
|
-
|
84
|
+
|
80
85
|
self
|
81
86
|
end
|
82
87
|
|
@@ -91,14 +96,16 @@ module Hexp
|
|
91
96
|
def rewrite(&block)
|
92
97
|
return @node if @node.text?
|
93
98
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
+
walk = MutableTreeWalk.new(@node)
|
100
|
+
|
101
|
+
until walk.end?
|
102
|
+
if comma_sequence.matches_path?(walk.path)
|
103
|
+
walk.replace!(block.call(walk.current))
|
99
104
|
end
|
100
|
-
|
101
|
-
|
105
|
+
walk.next!
|
106
|
+
end
|
107
|
+
|
108
|
+
walk.result
|
102
109
|
end
|
103
110
|
|
104
111
|
private
|
@@ -131,49 +138,6 @@ module Hexp
|
|
131
138
|
comma_sequence.matches?(@node)
|
132
139
|
end
|
133
140
|
|
134
|
-
# Consume the matching part of the comma sequence, return the rest
|
135
|
-
#
|
136
|
-
# Returns a new comma sequence with the parts removed that have been
|
137
|
-
# consumed by matching against this node. If no part matches, returns nil.
|
138
|
-
#
|
139
|
-
# @return [Hexp::CssSelector::CommaSequence]
|
140
|
-
#
|
141
|
-
# @api private
|
142
|
-
def next_comma_sequence
|
143
|
-
@next_comma_sequence ||= CssSelector::CommaSequence.new(consume_matching_heads)
|
144
|
-
end
|
145
|
-
|
146
|
-
# Recurse down a child down, passing in the remaining part of the selector
|
147
|
-
#
|
148
|
-
# @param [Hexp::Node] child
|
149
|
-
# One of the children of the node in this selection object
|
150
|
-
#
|
151
|
-
# @return [Hexp::Node::CssSelection]
|
152
|
-
#
|
153
|
-
# @api private
|
154
|
-
def next_selection_for(child)
|
155
|
-
self.class.new(child, next_comma_sequence)
|
156
|
-
end
|
157
|
-
|
158
|
-
# For each sequence in the comma sequence, remove the head if it matches
|
159
|
-
#
|
160
|
-
# For example, if this node is a `H[:div]`, and the selector is
|
161
|
-
# `span.foo, div a[:href]`, then the result of this method will be
|
162
|
-
# `span.foo, a[:href]`. This can then be used to match any child nodes.
|
163
|
-
#
|
164
|
-
# @return [Hexp::CssSelector::CommaSequence]
|
165
|
-
#
|
166
|
-
# @api private
|
167
|
-
def consume_matching_heads
|
168
|
-
comma_sequence.members.flat_map do |sequence|
|
169
|
-
if sequence.head_matches? @node
|
170
|
-
[sequence, sequence.drop_head]
|
171
|
-
else
|
172
|
-
[sequence]
|
173
|
-
end
|
174
|
-
end.reject(&:empty?)
|
175
|
-
end
|
176
|
-
|
177
141
|
end
|
178
142
|
end
|
179
143
|
end
|
data/lib/hexp/node/normalize.rb
CHANGED
@@ -43,6 +43,7 @@ module Hexp
|
|
43
43
|
#
|
44
44
|
# @api private
|
45
45
|
def normalized_attributes
|
46
|
+
return attributes if attributes.all? {|k,v| k.instance_of?(String) && v.instance_of?(String) }
|
46
47
|
Hash[*
|
47
48
|
attributes.flat_map do |key, value|
|
48
49
|
[key, value].map(&:to_s)
|
@@ -56,10 +57,12 @@ module Hexp
|
|
56
57
|
#
|
57
58
|
# @api private
|
58
59
|
def children
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
start = @raw[1].instance_of?(Hash) ? 2 : 1
|
61
|
+
if @raw[start].respond_to?(:to_ary)
|
62
|
+
@raw[start].to_ary
|
63
|
+
else
|
64
|
+
@raw.drop(start)
|
65
|
+
end
|
63
66
|
end
|
64
67
|
|
65
68
|
# Normalize the third element of a hexp node, the list of children
|
@@ -68,7 +71,11 @@ module Hexp
|
|
68
71
|
#
|
69
72
|
# @api private
|
70
73
|
def normalized_children
|
71
|
-
Hexp::List
|
74
|
+
if children.instance_of?(Hexp::List)
|
75
|
+
children
|
76
|
+
else
|
77
|
+
Hexp::List.new( children )
|
78
|
+
end
|
72
79
|
end
|
73
80
|
|
74
81
|
def self.coerce_node(node)
|
data/lib/hexp/text_node.rb
CHANGED
@@ -7,8 +7,6 @@ module Hexp
|
|
7
7
|
# converted to `TextNode` instances, so there is usually no reason to instantiate
|
8
8
|
# these yourself.
|
9
9
|
class TextNode < DelegateClass(String)
|
10
|
-
include Adamantium
|
11
|
-
|
12
10
|
# Inspect the TextNode
|
13
11
|
#
|
14
12
|
# This delegates to the underlying String, making it
|
data/lib/hexp/version.rb
CHANGED
@@ -0,0 +1,72 @@
|
|
1
|
+
RSpec.describe Hexp::MutableTreeWalk do
|
2
|
+
|
3
|
+
let(:node) { H[:ul, H[:p, [H[:li, 'foo', 'boo'], H[:li, 'bar']]]] }
|
4
|
+
let(:walk) { Hexp::MutableTreeWalk.new(node) }
|
5
|
+
|
6
|
+
it 'should start at the root' do
|
7
|
+
expect(walk.current).to eql node
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should not have a parent at the root' do
|
11
|
+
expect(walk.parent).to be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should descend to the children' do
|
15
|
+
walk.next!
|
16
|
+
expect(walk.current).to eql H[:p, [H[:li, ["foo", "boo"]], H[:li, ["bar"]]]]
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should go depth first' do
|
20
|
+
2.times { walk.next! }
|
21
|
+
expect(walk.current).to eql H[:li, 'foo', 'boo']
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should also do text nodes' do
|
25
|
+
3.times { walk.next! }
|
26
|
+
expect(walk.current).to eq 'foo'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should go left to right' do
|
30
|
+
4.times { walk.next! }
|
31
|
+
expect(walk.current).to eq 'boo'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should go back up and right' do
|
35
|
+
5.times { walk.next! }
|
36
|
+
expect(walk.current).to eql H[:li, 'bar']
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should finish on nil' do
|
40
|
+
7.times { walk.next! }
|
41
|
+
expect(walk.current).to be_nil
|
42
|
+
expect(walk.end?).to be true
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'stays at the end' do
|
46
|
+
8.times { walk.next! }
|
47
|
+
expect(walk.end?).to be true
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should allow replacements' do
|
51
|
+
2.times { walk.next! }
|
52
|
+
walk.replace! H[:foo]
|
53
|
+
6.times { walk.next! }
|
54
|
+
expect(walk.result).to eql H[:ul, H[:p, H[:foo], H[:li, 'bar']]]
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should allow replacements' do
|
58
|
+
7.times do
|
59
|
+
walk.next!
|
60
|
+
if !walk.end? && !walk.current.text? && walk.current.tag?(:li)
|
61
|
+
walk.replace! H[:span, walk.current]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
expect(walk.result).to eql H[:ul,
|
66
|
+
H[:p,
|
67
|
+
H[:span, H[:li, 'foo', 'boo']],
|
68
|
+
H[:span, H[:li, 'bar']]]]
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
end
|
@@ -18,7 +18,7 @@ describe Hexp::Node::CssSelection do
|
|
18
18
|
let(:hexp) { H[:span, {id: 'span-1'}, H[:span, id: 'span-2']] }
|
19
19
|
|
20
20
|
it 'should match all nodes of that tag' do
|
21
|
-
expect(selection.to_a).to eq [ H[:span, id: 'span-2']
|
21
|
+
expect(selection.to_a).to eq [ hexp, H[:span, id: 'span-2'] ]
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hexp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arne Brasseur
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sass
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.6'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: adamantium
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.2'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0.2'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: equalizer
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -193,6 +179,7 @@ files:
|
|
193
179
|
- lib/hexp/errors.rb
|
194
180
|
- lib/hexp/h.rb
|
195
181
|
- lib/hexp/list.rb
|
182
|
+
- lib/hexp/mutable_tree_walk.rb
|
196
183
|
- lib/hexp/node.rb
|
197
184
|
- lib/hexp/node/attributes.rb
|
198
185
|
- lib/hexp/node/children.rb
|
@@ -222,6 +209,7 @@ files:
|
|
222
209
|
- spec/unit/hexp/dsl_spec.rb
|
223
210
|
- spec/unit/hexp/h_spec.rb
|
224
211
|
- spec/unit/hexp/list_spec.rb
|
212
|
+
- spec/unit/hexp/mutable_tree_walk_spec.rb
|
225
213
|
- spec/unit/hexp/node/attr_spec.rb
|
226
214
|
- spec/unit/hexp/node/attributes_spec.rb
|
227
215
|
- spec/unit/hexp/node/children_spec.rb
|
@@ -280,6 +268,7 @@ test_files:
|
|
280
268
|
- spec/unit/hexp/dsl_spec.rb
|
281
269
|
- spec/unit/hexp/h_spec.rb
|
282
270
|
- spec/unit/hexp/list_spec.rb
|
271
|
+
- spec/unit/hexp/mutable_tree_walk_spec.rb
|
283
272
|
- spec/unit/hexp/node/attr_spec.rb
|
284
273
|
- spec/unit/hexp/node/attributes_spec.rb
|
285
274
|
- spec/unit/hexp/node/children_spec.rb
|