hexp 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,10 +8,26 @@ module Hexp
8
8
  class Rewriter
9
9
  include Hexp
10
10
 
11
+ # Initialize a rewriter with the node to operate on, and the action
12
+ #
13
+ # @param [Hexp::Node] node
14
+ # The root node of the tree to be altered
15
+ # @param [Proc] block
16
+ # The action to perform on each node
17
+ #
18
+ # @api public
11
19
  def initialize(node, block)
12
20
  @node, @block = node, block
13
21
  end
14
22
 
23
+ # Implicit Hexp conversion protocol
24
+ #
25
+ # A {Rewriter} is lazy, only when one of the {Hexp::DSL} methods is used,
26
+ # does the rewriting happen.
27
+ #
28
+ # @return [Hexp::Node]
29
+ #
30
+ # @api public
15
31
  def to_hexp
16
32
  @hexp ||= H[
17
33
  @node.tag,
@@ -24,16 +40,25 @@ module Hexp
24
40
 
25
41
  # Helper for rewrite
26
42
  #
27
- # @param blk [Proc] the block for rewriting
28
43
  # @return [Array<Hexp::Node>]
29
- # @api private
30
44
  #
45
+ # @api private
31
46
  def rewrite_children
32
47
  @node.children
33
- .flat_map {|child| child.rewrite &@block }
48
+ .flat_map {|child| child.rewrite(&@block) }
34
49
  .flat_map {|child| coerce_rewrite_response(@block.(child.to_hexp, @node)) || [child] }
35
50
  end
36
51
 
52
+ # Turn the response of a rewrite operation into something value
53
+ #
54
+ # The response can be a list of nodes, or a single node. If the response is
55
+ # `nil`, that is interpreted as removing the node.
56
+ #
57
+ # @param [nil,#to_hexp,#to_str,#to_ary] response
58
+ #
59
+ # @return [Array<Hexp::Node>]
60
+ #
61
+ # @api private
37
62
  def coerce_rewrite_response(response)
38
63
  return [] if response.nil?
39
64
 
@@ -1,6 +1,6 @@
1
1
  module Hexp
2
2
  class Node
3
- # Select nodes from a Hexp tree
3
+ # Subset of nodes from a Hexp tree
4
4
  #
5
5
  # This is what is backing the {Hexp::Node#select} method. It serves a double
6
6
  # purpose. At it's core it's an Enumerable for iterating over nodes that
@@ -17,13 +17,32 @@ module Hexp
17
17
  # # stick all links inside a <span class="link> ... </span>
18
18
  # hexp.select {|el| el.tag == 'a' }.wrap(:span, class: 'link')
19
19
  #
20
- class Selector
20
+ class Selection
21
21
  include Enumerable
22
22
 
23
+ # Initialize a selection with the root node, and the selection block used
24
+ # as the filtering criterion
25
+ #
26
+ # @param [Hexp::Node] node
27
+ # The root of the tree to select in
28
+ #
29
+ # @param [Proc] block
30
+ # A block that for a given node returns a truthy or falsey value
31
+ #
32
+ # @api private
23
33
  def initialize(node, block)
24
34
  @node, @select_block = node, block
25
35
  end
26
36
 
37
+ # Replace matching nodes
38
+ #
39
+ # Analogues to the main {Hexp::Node#rewrite} operation.
40
+ #
41
+ # @yieldparam [Hexp::Node]
42
+ #
43
+ # @return [Hexp::Node]
44
+ #
45
+ # @api public
27
46
  def rewrite(&block)
28
47
  @node.rewrite do |node, parent|
29
48
  if @select_block.(node)
@@ -34,18 +53,45 @@ module Hexp
34
53
  end
35
54
  end
36
55
 
56
+ # Set an attribute on all matching nodes
57
+ #
58
+ # @param [#to_s] name
59
+ # The attribute name
60
+ # @param [#to_s] value
61
+ # The attribute value
62
+ #
63
+ # @return [Hexp::Node]
64
+ # The new tree
65
+ #
66
+ # @api public
37
67
  def attr(name, value)
38
68
  rewrite do |node|
39
69
  node.attr(name, value)
40
70
  end
41
71
  end
42
72
 
73
+ # Wrap each matching node in a specific node
74
+ #
75
+ # @param [Symbol] tag
76
+ # The tag of the wrapping node
77
+ # @paeam [Hash] attributes
78
+ # The attributes of the node
79
+ #
80
+ # @return [Hexp::Node]
81
+ # The new tree of nodes
82
+ #
83
+ # @api public
43
84
  def wrap(tag, attributes = {})
44
85
  rewrite do |node|
45
86
  H[tag, attributes, [node]]
46
87
  end
47
88
  end
48
89
 
90
+ # Yield each matching node
91
+ #
92
+ # @yieldparam [Hexp::Node]
93
+ #
94
+ # @api public
49
95
  def each(&block)
50
96
  return to_enum(:each) unless block_given?
51
97
 
@@ -10,7 +10,7 @@ module Hexp
10
10
  # @api public
11
11
  #
12
12
  def call(node)
13
- return node.text if node.text?
13
+ return node.text if node.text? || node.cdata?
14
14
 
15
15
  unless node.attributes.empty?
16
16
  attrs = node.attributes.map do |key, value|
@@ -19,7 +19,7 @@ module Hexp
19
19
  attrs = Hash[attrs]
20
20
  end
21
21
 
22
- recurse = ->(node) { call(node) }
22
+ recurse = ->(next_node) { call(next_node) }
23
23
  H[node.name.to_sym, attrs, node.children.map(&recurse)]
24
24
  end
25
25
  end
@@ -140,7 +140,7 @@ module Hexp
140
140
  end
141
141
 
142
142
  def select(&block)
143
- Node::Selector.new(self, block)
143
+ Node::Selection.new(self, block)
144
144
  end
145
145
  end
146
146
  end
data/lib/hexp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hexp
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hexp::CssSelector::Universal do
4
+ it 'should match everything' do
5
+ expect(subject.matches? H[:section]).to be_true
6
+ end
7
+ end
@@ -63,4 +63,16 @@ describe Hexp::Node::Domize do
63
63
 
64
64
  it { should_not dom_eq(dom) }
65
65
  end
66
+
67
+ context 'with the :html5 option' do
68
+ let(:hexp) { Hexp::Node[:html] }
69
+
70
+ it 'should set a HTML5 style doctype' do
71
+ dtd = hexp.to_dom(html5: true).children.first
72
+ expect(dtd).to be_a Nokogiri::XML::DTD
73
+ expect(dtd.name).to be_nil
74
+ expect(dtd.external_id).to be_nil
75
+ expect(dtd.system_id).to be_nil
76
+ end
77
+ end
66
78
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Hexp::Node::Selector do
4
- subject(:selector) { Hexp::Node::Selector.new(hexp, block) }
3
+ describe Hexp::Node::Selection do
4
+ subject(:selection) { Hexp::Node::Selection.new(hexp, block) }
5
5
  let(:yielded_elements) { [] }
6
6
  let(:block) { proc {|el| yielded_elements << el } }
7
7
  let(:hexp) { H[:div, [[:span]]] }
@@ -10,7 +10,7 @@ describe Hexp::Node::Selector do
10
10
  let(:block) { proc {|el| el.tag == :span} }
11
11
 
12
12
  it 'should enumerate elements for which the block returns trueish' do
13
- expect(selector.to_a).to eq [H[:span]]
13
+ expect(selection.to_a).to eq [H[:span]]
14
14
  end
15
15
  end
16
16
 
@@ -18,7 +18,7 @@ describe Hexp::Node::Selector do
18
18
  let(:block) { proc {|el| el.tag == :span} }
19
19
 
20
20
  it 'should perform them on elements that match' do
21
- expect(selector.attr('class', 'matched').to_hexp).to eq(
21
+ expect(selection.attr('class', 'matched').to_hexp).to eq(
22
22
  H[:div, [[:span, {class: 'matched'}]]]
23
23
  )
24
24
  end
@@ -28,7 +28,7 @@ describe Hexp::Node::Selector do
28
28
  let(:block) { proc {|el| el.tag == :a} }
29
29
 
30
30
  it 'should be able to wrap element' do
31
- expect(selector.wrap(:li).to_hexp).to eq(
31
+ expect(selection.wrap(:li).to_hexp).to eq(
32
32
  H[:ul, [[:li, H[:a, href: 'foo']], [:li, H[:a, href: 'bar']]]]
33
33
  )
34
34
  end
@@ -39,7 +39,7 @@ describe Hexp::Node::Selector do
39
39
  let(:block) { proc {|el| el.tag == :a} }
40
40
 
41
41
  it 'should work on matching elements, and skip the rest' do
42
- expect(selector.rewrite{ H[:br] }.to_hexp).to eq H[:ul, [[:br], [:span]]]
42
+ expect(selection.rewrite{ H[:br] }.to_hexp).to eq H[:ul, [[:br], [:span]]]
43
43
  end
44
44
  end
45
45
  end
@@ -49,12 +49,12 @@ describe Hexp::Node::Selector do
49
49
 
50
50
  it 'should be lazy' do
51
51
  expect(block).to_not receive(:call)
52
- selector
52
+ selection
53
53
  end
54
54
 
55
55
  it 'should yield the root element when realized' do
56
56
  expect(block).to receive(:call).once.with(H[:div])
57
- selector.each {}
57
+ selection.each {}
58
58
  end
59
59
  end
60
60
 
@@ -65,7 +65,7 @@ describe Hexp::Node::Selector do
65
65
  [:span, "world"]]]}
66
66
 
67
67
  it 'should traverse the whole tree once, depth-first' do
68
- selector.each {}
68
+ selection.each {}
69
69
  expect(yielded_elements).to eq [
70
70
  Hexp::TextNode.new("hello"),
71
71
  H[:span, "hello"],
@@ -20,4 +20,14 @@ describe Hexp, 'parse' do
20
20
  it 'should parse attributes' do
21
21
  expect(Hexp.parse('<a href="pretty">Ciao Bella</a>')).to eq H[:a, {href: 'pretty'}, 'Ciao Bella']
22
22
  end
23
+
24
+ it 'should parse style tags' do
25
+ expect(Hexp.parse('<html><head><style type="text/css">h1 {font-weigth: 400;}</style></head></html>')).to eq(
26
+ H[:html,
27
+ H[:head,
28
+ H[:style, {type: 'text/css'}, 'h1 {font-weigth: 400;}']
29
+ ]
30
+ ]
31
+ )
32
+ end
23
33
  end
metadata CHANGED
@@ -1,112 +1,113 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Arne Brasseur
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-18 00:00:00.000000000 Z
11
+ date: 2014-01-28 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
14
+ prerelease: false
15
15
  name: sass
16
- type: :runtime
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
18
  - - ~>
21
19
  - !ruby/object:Gem::Version
22
20
  version: '3.2'
21
+ type: :runtime
23
22
  version_requirements: !ruby/object:Gem::Requirement
24
- none: false
25
23
  requirements:
26
24
  - - ~>
27
25
  - !ruby/object:Gem::Version
28
26
  version: '3.2'
29
- prerelease: false
30
27
  - !ruby/object:Gem::Dependency
28
+ prerelease: false
31
29
  name: nokogiri
32
- type: :runtime
33
30
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
31
  requirements:
36
32
  - - ~>
37
33
  - !ruby/object:Gem::Version
38
34
  version: '1.6'
35
+ type: :runtime
39
36
  version_requirements: !ruby/object:Gem::Requirement
40
- none: false
41
37
  requirements:
42
38
  - - ~>
43
39
  - !ruby/object:Gem::Version
44
40
  version: '1.6'
45
- prerelease: false
46
41
  - !ruby/object:Gem::Dependency
42
+ prerelease: false
47
43
  name: ice_nine
48
- type: :runtime
49
44
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
45
  requirements:
52
46
  - - ~>
53
47
  - !ruby/object:Gem::Version
54
- version: '0.8'
48
+ version: '0.9'
49
+ type: :runtime
55
50
  version_requirements: !ruby/object:Gem::Requirement
56
- none: false
57
51
  requirements:
58
52
  - - ~>
59
53
  - !ruby/object:Gem::Version
60
- version: '0.8'
61
- prerelease: false
54
+ version: '0.9'
62
55
  - !ruby/object:Gem::Dependency
56
+ prerelease: false
63
57
  name: equalizer
64
- type: :runtime
65
58
  requirement: !ruby/object:Gem::Requirement
66
- none: false
67
59
  requirements:
68
60
  - - ~>
69
61
  - !ruby/object:Gem::Version
70
62
  version: '0.0'
63
+ type: :runtime
71
64
  version_requirements: !ruby/object:Gem::Requirement
72
- none: false
73
65
  requirements:
74
66
  - - ~>
75
67
  - !ruby/object:Gem::Version
76
68
  version: '0.0'
77
- prerelease: false
78
69
  - !ruby/object:Gem::Dependency
70
+ prerelease: false
79
71
  name: rake
80
- type: :development
81
72
  requirement: !ruby/object:Gem::Requirement
82
- none: false
83
73
  requirements:
84
74
  - - ~>
85
75
  - !ruby/object:Gem::Version
86
76
  version: '10.1'
77
+ type: :development
87
78
  version_requirements: !ruby/object:Gem::Requirement
88
- none: false
89
79
  requirements:
90
80
  - - ~>
91
81
  - !ruby/object:Gem::Version
92
82
  version: '10.1'
93
- prerelease: false
94
83
  - !ruby/object:Gem::Dependency
84
+ prerelease: false
95
85
  name: rspec
96
- type: :development
97
86
  requirement: !ruby/object:Gem::Requirement
98
- none: false
99
87
  requirements:
100
88
  - - ~>
101
89
  - !ruby/object:Gem::Version
102
90
  version: '2.14'
91
+ type: :development
103
92
  version_requirements: !ruby/object:Gem::Requirement
104
- none: false
105
93
  requirements:
106
94
  - - ~>
107
95
  - !ruby/object:Gem::Version
108
96
  version: '2.14'
97
+ - !ruby/object:Gem::Dependency
109
98
  prerelease: false
99
+ name: benchmark_suite
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ~>
103
+ - !ruby/object:Gem::Version
104
+ version: '1.0'
105
+ type: :development
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
110
111
  description: HTML expressions
111
112
  email:
112
113
  - arne@arnebrasseur.net
@@ -117,14 +118,15 @@ extra_rdoc_files:
117
118
  files:
118
119
  - .gitignore
119
120
  - .travis.yml
121
+ - .yardopts
120
122
  - Changelog.md
121
123
  - Gemfile
122
124
  - Gemfile.devtools
123
125
  - Gemfile.lock
124
- - LICENSE.md
126
+ - LICENSE
125
127
  - README.md
126
128
  - Rakefile
127
- - SPEC.md
129
+ - bench/node/rewrite_bench.rb
128
130
  - config/devtools.yml
129
131
  - config/flay.yml
130
132
  - config/flog.yml
@@ -157,13 +159,12 @@ files:
157
159
  - lib/hexp/node/normalize.rb
158
160
  - lib/hexp/node/pp.rb
159
161
  - lib/hexp/node/rewriter.rb
160
- - lib/hexp/node/selector.rb
162
+ - lib/hexp/node/selection.rb
161
163
  - lib/hexp/nokogiri/equality.rb
162
164
  - lib/hexp/nokogiri/reader.rb
163
165
  - lib/hexp/sass/selector_parser.rb
164
166
  - lib/hexp/text_node.rb
165
167
  - lib/hexp/version.rb
166
- - notes
167
168
  - spec/integration/literal_syntax_spec.rb
168
169
  - spec/shared_helper.rb
169
170
  - spec/spec_helper.rb
@@ -174,6 +175,7 @@ files:
174
175
  - spec/unit/hexp/css_selector/element_spec.rb
175
176
  - spec/unit/hexp/css_selector/parser_spec.rb
176
177
  - spec/unit/hexp/css_selector/simple_sequence_spec.rb
178
+ - spec/unit/hexp/css_selector/universal_spec.rb
177
179
  - spec/unit/hexp/dsl_spec.rb
178
180
  - spec/unit/hexp/h_spec.rb
179
181
  - spec/unit/hexp/list_spec.rb
@@ -186,7 +188,7 @@ files:
186
188
  - spec/unit/hexp/node/normalize_spec.rb
187
189
  - spec/unit/hexp/node/pp_spec.rb
188
190
  - spec/unit/hexp/node/rewrite_spec.rb
189
- - spec/unit/hexp/node/selector_spec.rb
191
+ - spec/unit/hexp/node/selection_spec.rb
190
192
  - spec/unit/hexp/node/text_spec.rb
191
193
  - spec/unit/hexp/node/to_dom_spec.rb
192
194
  - spec/unit/hexp/node/to_hexp_spec.rb
@@ -199,33 +201,26 @@ files:
199
201
  homepage: https://github.com/plexus/hexp
200
202
  licenses:
201
203
  - MIT
204
+ metadata: {}
202
205
  post_install_message:
203
206
  rdoc_options: []
204
207
  require_paths:
205
208
  - lib
206
209
  required_ruby_version: !ruby/object:Gem::Requirement
207
- none: false
208
210
  requirements:
209
211
  - - ! '>='
210
212
  - !ruby/object:Gem::Version
211
213
  version: '0'
212
- segments:
213
- - 0
214
- hash: -1985616243020717322
215
214
  required_rubygems_version: !ruby/object:Gem::Requirement
216
- none: false
217
215
  requirements:
218
216
  - - ! '>='
219
217
  - !ruby/object:Gem::Version
220
218
  version: '0'
221
- segments:
222
- - 0
223
- hash: -1985616243020717322
224
219
  requirements: []
225
220
  rubyforge_project:
226
- rubygems_version: 1.8.23
221
+ rubygems_version: 2.2.1
227
222
  signing_key:
228
- specification_version: 3
223
+ specification_version: 4
229
224
  summary: HTML expressions
230
225
  test_files:
231
226
  - spec/integration/literal_syntax_spec.rb
@@ -238,6 +233,7 @@ test_files:
238
233
  - spec/unit/hexp/css_selector/element_spec.rb
239
234
  - spec/unit/hexp/css_selector/parser_spec.rb
240
235
  - spec/unit/hexp/css_selector/simple_sequence_spec.rb
236
+ - spec/unit/hexp/css_selector/universal_spec.rb
241
237
  - spec/unit/hexp/dsl_spec.rb
242
238
  - spec/unit/hexp/h_spec.rb
243
239
  - spec/unit/hexp/list_spec.rb
@@ -250,7 +246,7 @@ test_files:
250
246
  - spec/unit/hexp/node/normalize_spec.rb
251
247
  - spec/unit/hexp/node/pp_spec.rb
252
248
  - spec/unit/hexp/node/rewrite_spec.rb
253
- - spec/unit/hexp/node/selector_spec.rb
249
+ - spec/unit/hexp/node/selection_spec.rb
254
250
  - spec/unit/hexp/node/text_spec.rb
255
251
  - spec/unit/hexp/node/to_dom_spec.rb
256
252
  - spec/unit/hexp/node/to_hexp_spec.rb