hexp 0.0.1 → 0.2.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.
- data/.travis.yml +12 -3
- data/Changelog.md +9 -0
- data/Gemfile +3 -5
- data/Gemfile.devtools +20 -18
- data/Gemfile.lock +97 -84
- data/Rakefile +16 -0
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/reek.yml +42 -18
- data/config/rubocop.yml +31 -0
- data/config/yardstick.yml +39 -1
- data/examples/from_nokogiri.rb +77 -0
- data/examples/selector_rewriter_chaining.rb +14 -0
- data/examples/todo.rb +138 -0
- data/examples/widget.rb +64 -0
- data/hexp.gemspec +8 -3
- data/lib/hexp.rb +103 -2
- data/lib/hexp/builder.rb +256 -0
- data/lib/hexp/css_selector.rb +205 -0
- data/lib/hexp/css_selector/parser.rb +74 -0
- data/lib/hexp/css_selector/sass_parser.rb +22 -0
- data/lib/hexp/dom.rb +0 -2
- data/lib/hexp/dsl.rb +27 -0
- data/lib/hexp/errors.rb +21 -0
- data/lib/hexp/h.rb +5 -2
- data/lib/hexp/list.rb +67 -9
- data/lib/hexp/node.rb +197 -41
- data/lib/hexp/node/attributes.rb +176 -0
- data/lib/hexp/node/children.rb +44 -0
- data/lib/hexp/node/css_selection.rb +73 -0
- data/lib/hexp/node/domize.rb +52 -6
- data/lib/hexp/node/normalize.rb +19 -9
- data/lib/hexp/node/pp.rb +32 -0
- data/lib/hexp/node/rewriter.rb +52 -0
- data/lib/hexp/node/selector.rb +59 -0
- data/lib/hexp/nokogiri/equality.rb +61 -0
- data/lib/hexp/nokogiri/reader.rb +27 -0
- data/lib/hexp/sass/selector_parser.rb +4 -0
- data/lib/hexp/text_node.rb +129 -9
- data/lib/hexp/version.rb +1 -1
- data/notes +34 -0
- data/spec/shared_helper.rb +6 -0
- data/spec/spec_helper.rb +2 -6
- data/spec/unit/hexp/builder_spec.rb +101 -0
- data/spec/unit/hexp/css_selector/attribute_spec.rb +137 -0
- data/spec/unit/hexp/css_selector/class_spec.rb +15 -0
- data/spec/unit/hexp/css_selector/comma_sequence_spec.rb +20 -0
- data/spec/unit/hexp/css_selector/element_spec.rb +11 -0
- data/spec/unit/hexp/css_selector/parser_spec.rb +51 -0
- data/spec/unit/hexp/css_selector/simple_sequence_spec.rb +48 -0
- data/spec/unit/hexp/dsl_spec.rb +55 -0
- data/spec/unit/hexp/h_spec.rb +38 -0
- data/spec/unit/hexp/list_spec.rb +19 -0
- data/spec/unit/hexp/node/attr_spec.rb +55 -0
- data/spec/unit/hexp/node/attributes_spec.rb +125 -0
- data/spec/unit/hexp/node/children_spec.rb +33 -0
- data/spec/unit/hexp/node/class_spec.rb +37 -0
- data/spec/unit/hexp/node/css_selection_spec.rb +86 -0
- data/spec/unit/hexp/node/normalize_spec.rb +12 -6
- data/spec/unit/hexp/node/rewrite_spec.rb +67 -30
- data/spec/unit/hexp/node/selector_spec.rb +78 -0
- data/spec/unit/hexp/node/text_spec.rb +7 -0
- data/spec/unit/hexp/node/to_dom_spec.rb +1 -1
- data/spec/unit/hexp/nokogiri/reader_spec.rb +8 -0
- data/spec/unit/hexp/parse_spec.rb +23 -0
- data/spec/unit/hexp/text_node_spec.rb +25 -0
- data/spec/unit/hexp_spec.rb +33 -0
- metadata +129 -16
- data/lib/hexp/format_error.rb +0 -8
data/config/rubocop.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
AllCops:
|
2
|
+
Includes:
|
3
|
+
- '../**/*.rake'
|
4
|
+
Excludes:
|
5
|
+
- '../vendor/**'
|
6
|
+
|
7
|
+
# Avoid parameter lists longer than five parameters.
|
8
|
+
ParameterLists:
|
9
|
+
Max: 3
|
10
|
+
CountKeywordArgs: true
|
11
|
+
|
12
|
+
# Avoid more than `Max` levels of nesting.
|
13
|
+
BlockNesting:
|
14
|
+
Max: 3
|
15
|
+
|
16
|
+
# Align with the style guide.
|
17
|
+
CollectionMethods:
|
18
|
+
PreferredMethods:
|
19
|
+
collect: 'map'
|
20
|
+
inject: 'reduce'
|
21
|
+
find: 'detect'
|
22
|
+
find_all: 'select'
|
23
|
+
|
24
|
+
# Do not force public/protected/private keyword to be indented at the same
|
25
|
+
# level as the def keyword. My personal preference is to outdent these keywords
|
26
|
+
# because I think when scanning code it makes it easier to identify the
|
27
|
+
# sections of code and visually separate them. When the keyword is at the same
|
28
|
+
# level I think it sort of blends in with the def keywords and makes it harder
|
29
|
+
# to scan the code and see where the sections are.
|
30
|
+
AccessControl:
|
31
|
+
Enabled: false
|
data/config/yardstick.yml
CHANGED
@@ -1,2 +1,40 @@
|
|
1
1
|
---
|
2
|
-
threshold:
|
2
|
+
threshold: 93.7
|
3
|
+
rules:
|
4
|
+
ApiTag::Presence:
|
5
|
+
enabled: true
|
6
|
+
exclude: []
|
7
|
+
ApiTag::Inclusion:
|
8
|
+
enabled: true
|
9
|
+
exclude: []
|
10
|
+
ApiTag::ProtectedMethod:
|
11
|
+
enabled: true
|
12
|
+
exclude: []
|
13
|
+
ApiTag::PrivateMethod:
|
14
|
+
enabled: false
|
15
|
+
exclude: []
|
16
|
+
ExampleTag:
|
17
|
+
enabled: false
|
18
|
+
exclude:
|
19
|
+
- Hexp::Nokogiri::Equality#call
|
20
|
+
- Hexp::Nokogiri::Equality#equal_class?
|
21
|
+
- Hexp::Nokogiri::Equality#equal_name?
|
22
|
+
- Hexp::Nokogiri::Equality#equal_children?
|
23
|
+
- Hexp::Nokogiri::Equality#compare_children
|
24
|
+
- Hexp::Nokogiri::Equality#equal_attributes?
|
25
|
+
- Hexp::Nokogiri::Equality#equal_text?
|
26
|
+
ReturnTag:
|
27
|
+
enabled: true
|
28
|
+
exclude: []
|
29
|
+
Summary::Presence:
|
30
|
+
enabled: true
|
31
|
+
exclude: []
|
32
|
+
Summary::Length:
|
33
|
+
enabled: true
|
34
|
+
exclude: []
|
35
|
+
Summary::Delimiter:
|
36
|
+
enabled: true
|
37
|
+
exclude: []
|
38
|
+
Summary::SingleLine:
|
39
|
+
enabled: true
|
40
|
+
exclude: []
|
@@ -0,0 +1,77 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
+
|
3
|
+
require 'hexp'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
module Hexp
|
7
|
+
def self.from_nokogiri(node)
|
8
|
+
attrs = node.attributes.map do |k,v|
|
9
|
+
[k.to_sym, v.value]
|
10
|
+
end
|
11
|
+
children = node.children.map do |child|
|
12
|
+
case child
|
13
|
+
when ::Nokogiri::XML::Text
|
14
|
+
Hexp::TextNode.new(child.text)
|
15
|
+
when ::Nokogiri::XML::Node
|
16
|
+
from_nokogiri(child)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
H[node.name.to_sym, Hash[attrs], children]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Nokogiri::XML::Node
|
24
|
+
def to_hexp
|
25
|
+
Hexp.from_nokogiri(self)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Nokogiri::XML::Document
|
30
|
+
end
|
31
|
+
|
32
|
+
describe Hexp, 'from_nokigiri' do
|
33
|
+
def doc
|
34
|
+
@doc ||= Nokogiri::HTML::Document.new
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should convert a single node' do
|
38
|
+
h3 = Nokogiri::XML::Node.new "h3", doc
|
39
|
+
Hexp.from_nokogiri(h3).must_equal H[:h3]
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should extract arguments, if there are any' do
|
43
|
+
h3 = Nokogiri::XML::Node.new "h3", doc
|
44
|
+
h3[:class] = 'foo'
|
45
|
+
Hexp.from_nokogiri(h3).must_equal H[:h3, {class: 'foo'}]
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should convert children' do
|
49
|
+
div = Nokogiri::XML::Node.new "div", doc
|
50
|
+
p = Nokogiri::XML::Node.new "p", doc
|
51
|
+
span = Nokogiri::XML::Node.new "span", doc
|
52
|
+
div << p
|
53
|
+
div << span
|
54
|
+
|
55
|
+
Hexp.from_nokogiri(div).must_equal H[:div, [[:p], [:span]]]
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should convert text nodes' do
|
59
|
+
div = Nokogiri::XML::Node.new "div", doc
|
60
|
+
p = Nokogiri::XML::Node.new "p", doc
|
61
|
+
text = Nokogiri::XML::Text.new "text", doc
|
62
|
+
div << p
|
63
|
+
div << text
|
64
|
+
|
65
|
+
Hexp.from_nokogiri(div).must_equal H[:div, [[:p], "text"]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# >> Run options: --seed 54619
|
70
|
+
# >>
|
71
|
+
# >> # Running tests:
|
72
|
+
# >>
|
73
|
+
# >> ....
|
74
|
+
# >>
|
75
|
+
# >> Finished tests in 0.003244s, 1233.0547 tests/s, 1233.0547 assertions/s.
|
76
|
+
# >>
|
77
|
+
# >> 4 tests, 4 assertions, 0 failures, 0 errors, 0 skips
|
@@ -0,0 +1,14 @@
|
|
1
|
+
d=H[:div, %w(foo bar baz).map{|klz| [:p, class: klz]}]
|
2
|
+
|
3
|
+
#=> H[:div, [H[:p, {"class"=>"foo"}], H[:p, {"class"=>"bar"}], H[:p, {"class"=>"baz"}]]]
|
4
|
+
|
5
|
+
d.select {|node|node.class? 'bar'} #=> #<Hexp::Node::Selector>
|
6
|
+
.wrap(:span) #=> #<Hexp::Node::Rewriter>
|
7
|
+
.attr('data-x', '77') #=> #<Hexp::Node::Rewriter>
|
8
|
+
.wrap(:foo, 'hello' => 'jow') #=> #<Hexp::Node::Rewriter>
|
9
|
+
.attr('faz', 'foz').to_html(:include_doctype => false)
|
10
|
+
|
11
|
+
# <div>
|
12
|
+
# <p class="foo"></p>
|
13
|
+
# <foo hello="jow" faz="foz"><span data-x="77"><p class="bar"></p></span></foo><p class="baz"></p>
|
14
|
+
# </div>
|
data/examples/todo.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
$:.unshift File.expand_path('../../examples', __FILE__)
|
3
|
+
|
4
|
+
require 'sinatra'
|
5
|
+
require 'hexp'
|
6
|
+
require 'widget'
|
7
|
+
|
8
|
+
class EntryStore
|
9
|
+
def self.store(entry)
|
10
|
+
@counter ||= 0
|
11
|
+
@entries ||= {}
|
12
|
+
entry.id = (@counter+=1) unless entry.id
|
13
|
+
@entries[entry.id] = entry
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(id)
|
17
|
+
@entries[id]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.all
|
21
|
+
@entries ||= {}
|
22
|
+
@entries.values || []
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.delete(id)
|
26
|
+
@entries.delete(id)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Entry < Widget(:span)
|
31
|
+
attribute :id, Integer
|
32
|
+
attribute :description, String
|
33
|
+
|
34
|
+
def widget
|
35
|
+
[ description ]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class EntryList
|
40
|
+
def initialize(entries)
|
41
|
+
@entries = entries
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hexp
|
45
|
+
H[:ul,
|
46
|
+
@entries.map do |entry|
|
47
|
+
H[:li, entry]
|
48
|
+
end
|
49
|
+
]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class AddEntryForm
|
54
|
+
def to_hexp
|
55
|
+
H[:form, {method: 'POST', action: '/'}, [
|
56
|
+
H[:input, {type: 'text', name: 'entry_description'}],
|
57
|
+
H[:input, {type: 'submit'}, "Add"]
|
58
|
+
]
|
59
|
+
]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Layout
|
64
|
+
include Hexp
|
65
|
+
|
66
|
+
def initialize(*contents)
|
67
|
+
@contents = contents
|
68
|
+
p @contents
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_hexp
|
72
|
+
H[:html, [
|
73
|
+
H[:head],
|
74
|
+
H[:body, @contents ]
|
75
|
+
]
|
76
|
+
]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class ListPage
|
81
|
+
include Hexp
|
82
|
+
TITLE = 'Todo List'
|
83
|
+
|
84
|
+
def to_hexp
|
85
|
+
hexp = Layout.new(
|
86
|
+
EntryList.new(EntryStore.all),
|
87
|
+
AddEntryForm.new
|
88
|
+
)
|
89
|
+
hexp = add_title(hexp)
|
90
|
+
hexp = wrap_entry_forms(hexp)
|
91
|
+
end
|
92
|
+
|
93
|
+
def title
|
94
|
+
H[:title, TITLE]
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_title(tree)
|
98
|
+
tree.rewrite do |node|
|
99
|
+
if node.tag == :head
|
100
|
+
H[:head, node.attributes, node.children + [title]]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def wrap_entry_forms(tree)
|
106
|
+
tree.rewrite do |node|
|
107
|
+
if node.class? 'entry'
|
108
|
+
H[:form, {method: 'POST', action: "/#{node.attr('data-id')}"}, [
|
109
|
+
node,
|
110
|
+
H[:input, type: 'hidden', name: '_method', value: 'DELETE'],
|
111
|
+
H[:input, type: 'submit', value: '-']
|
112
|
+
]
|
113
|
+
]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
get '/' do
|
120
|
+
ListPage.new.to_html
|
121
|
+
end
|
122
|
+
|
123
|
+
post '/' do
|
124
|
+
@entry = Entry.new(description: params['entry_description'])
|
125
|
+
EntryStore.store(@entry)
|
126
|
+
|
127
|
+
ListPage.new.to_html
|
128
|
+
end
|
129
|
+
|
130
|
+
delete '/:id' do
|
131
|
+
EntryStore.delete params[:id].to_i
|
132
|
+
|
133
|
+
ListPage.new.to_html
|
134
|
+
end
|
135
|
+
|
136
|
+
get '/handlebars' do
|
137
|
+
Entry.handlebars.to_html
|
138
|
+
end
|
data/examples/widget.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
$:.unshift File.expand_path '../../lib', __FILE__
|
2
|
+
|
3
|
+
require 'hexp'
|
4
|
+
require 'virtus'
|
5
|
+
|
6
|
+
class Widget
|
7
|
+
include Hexp
|
8
|
+
include Virtus
|
9
|
+
|
10
|
+
attribute :tag, Symbol, default: :div
|
11
|
+
attribute :data, Hash
|
12
|
+
|
13
|
+
def to_hexp
|
14
|
+
H[tag, html_attributes, widget]
|
15
|
+
end
|
16
|
+
|
17
|
+
def html_attributes
|
18
|
+
attrs = Hash[data.map {|k,v| ["data-#{k}", v]}].merge(class: [self.class.widget_name, 'widget']*' ' )
|
19
|
+
if attribute_set.any?{|attribute| attribute.name == :id} && self.id
|
20
|
+
attrs['data-id'] = self.id
|
21
|
+
end
|
22
|
+
attrs
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.widget_name
|
26
|
+
self.name.downcase
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.handlebars
|
30
|
+
H[:script, {:type => 'application/x-handlebars-template', :id => widget_name+'-template'},
|
31
|
+
self.new(
|
32
|
+
Hash[
|
33
|
+
attribute_set
|
34
|
+
.reject {|attribute| [:data, :tag].include?(attribute.name) }
|
35
|
+
.map {|attribute| [attribute.name, "{{#{attribute.name}}}"] }
|
36
|
+
]
|
37
|
+
)
|
38
|
+
]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def Widget(tag)
|
43
|
+
Class.new(Widget) do
|
44
|
+
attribute :tag, Symbol, default: tag
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# class Entry < Widget(:p)
|
50
|
+
# attribute :name, String
|
51
|
+
# attribute :date, String # !> assigned but unused variable - type
|
52
|
+
|
53
|
+
# def widget
|
54
|
+
# [
|
55
|
+
# [:span, name],
|
56
|
+
# [:span, date]
|
57
|
+
# ]
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
|
61
|
+
# puts Entry.new(name: 'foo', date: '2013-06-17', data: {id: 17}).to_html
|
62
|
+
# puts
|
63
|
+
# puts Entry.handlebars.to_html
|
64
|
+
# !> instance variable @default not initialized
|
data/hexp.gemspec
CHANGED
@@ -10,13 +10,18 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.description = 'HTML expressions'
|
11
11
|
gem.summary = gem.description
|
12
12
|
gem.homepage = 'https://github.com/plexus/hexp'
|
13
|
+
gem.license = 'MIT'
|
13
14
|
|
14
15
|
gem.require_paths = %w[lib]
|
15
16
|
gem.files = `git ls-files`.split($/)
|
16
17
|
gem.test_files = `git ls-files -- spec`.split($/)
|
17
18
|
gem.extra_rdoc_files = %w[README.md]
|
18
19
|
|
19
|
-
gem.
|
20
|
-
gem.
|
21
|
-
gem.
|
20
|
+
gem.add_runtime_dependency 'sass' , '~> 3.2'
|
21
|
+
gem.add_runtime_dependency 'nokogiri' , '~> 1.6'
|
22
|
+
gem.add_runtime_dependency 'ice_nine' , '~> 0.8'
|
23
|
+
gem.add_runtime_dependency 'equalizer' , '~> 0.0'
|
24
|
+
|
25
|
+
gem.add_development_dependency 'rake', '~> 10.1'
|
26
|
+
gem.add_development_dependency 'rspec', '~> 2.14'
|
22
27
|
end
|
data/lib/hexp.rb
CHANGED
@@ -1,27 +1,128 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
require 'forwardable'
|
3
3
|
|
4
|
-
require 'nokogiri'
|
4
|
+
require 'nokogiri' # TODO => replace with Builder
|
5
|
+
require 'sass'
|
5
6
|
require 'ice_nine'
|
6
7
|
require 'equalizer'
|
7
8
|
|
8
9
|
module Hexp
|
10
|
+
# Inject the Hexp::DSL module into classes that include Hexp
|
11
|
+
#
|
12
|
+
# @param klazz [Class] The class that included Hexp
|
13
|
+
#
|
14
|
+
# @return [Class]
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def self.included(klazz)
|
18
|
+
klazz.send(:include, Hexp::DSL)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Deep freeze an object
|
22
|
+
#
|
23
|
+
# Delegates to IceNine
|
24
|
+
#
|
25
|
+
# @param args [Array] arguments to pass on
|
26
|
+
# @return Object
|
27
|
+
# @api private
|
28
|
+
#
|
9
29
|
def self.deep_freeze(*args)
|
10
30
|
IceNine.deep_freeze(*args)
|
11
31
|
end
|
32
|
+
|
33
|
+
# Variant of ::Array with slightly modified semantics
|
34
|
+
#
|
35
|
+
# Array() is often used to wrap a value in an Array, unless it's already
|
36
|
+
# an array. However if your object implements #to_a, then Array() will use
|
37
|
+
# that value. Because of this objects that aren't Array-like will get
|
38
|
+
# converted as well, such as Struct objects.
|
39
|
+
#
|
40
|
+
# This implementation relies on #to_ary, which signals that the Object is
|
41
|
+
# a drop-in replacement for an actual Array.
|
42
|
+
#
|
43
|
+
# @param arg [Object]
|
44
|
+
# @return [Array]
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
def self.Array(arg)
|
48
|
+
if arg.respond_to? :to_ary
|
49
|
+
arg.to_ary
|
50
|
+
else
|
51
|
+
[ arg ]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Parse HTML to Hexp
|
56
|
+
#
|
57
|
+
# The input have a single root element. If there are multiple only the first
|
58
|
+
# will be converted. If there is no root element (e.g. an empty document, or
|
59
|
+
# only a DTD or comment) then an error is raised
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# Hexp.parse('<div>hello</div>') #=> H[:div, "hello"]
|
63
|
+
#
|
64
|
+
# @param html [String] A HTML document
|
65
|
+
# @return [Hexp::Node]
|
66
|
+
# @api public
|
67
|
+
#
|
68
|
+
def self.parse(html)
|
69
|
+
root = Nokogiri(html).root
|
70
|
+
raise Hexp::ParseError, "Failed to parse HTML : no document root" if root.nil?
|
71
|
+
Hexp::Nokogiri::Reader.new.call(root)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Use builder syntax to create a Hexp
|
75
|
+
#
|
76
|
+
# (see Hexp::Builder)
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# list = Hexp.build do
|
80
|
+
# ul do
|
81
|
+
# 3.times do |i|
|
82
|
+
# li i.to_s
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# @param args [Array]
|
88
|
+
# @return [Hexp::Builder]
|
89
|
+
# @api public
|
90
|
+
#
|
91
|
+
def self.build(*args, &block)
|
92
|
+
Hexp::Builder.new(*args, &block)
|
93
|
+
end
|
94
|
+
|
12
95
|
end
|
13
96
|
|
14
97
|
require 'hexp/version'
|
98
|
+
require 'hexp/dsl'
|
99
|
+
|
100
|
+
|
101
|
+
require 'hexp/node/attributes'
|
102
|
+
require 'hexp/node/children'
|
15
103
|
|
16
104
|
require 'hexp/node'
|
17
105
|
require 'hexp/node/normalize'
|
18
106
|
require 'hexp/node/domize'
|
19
107
|
require 'hexp/node/pp'
|
108
|
+
require 'hexp/node/rewriter'
|
109
|
+
require 'hexp/node/selector'
|
110
|
+
require 'hexp/node/css_selection'
|
20
111
|
|
21
112
|
require 'hexp/text_node'
|
22
113
|
require 'hexp/list'
|
23
114
|
require 'hexp/dom'
|
24
115
|
|
25
|
-
require 'hexp/
|
116
|
+
require 'hexp/css_selector'
|
117
|
+
require 'hexp/css_selector/sass_parser'
|
118
|
+
require 'hexp/css_selector/parser'
|
119
|
+
|
120
|
+
require 'hexp/errors'
|
121
|
+
|
122
|
+
require 'hexp/nokogiri/equality' # TODO => replace this with equivalent-xml
|
123
|
+
require 'hexp/nokogiri/reader'
|
124
|
+
require 'hexp/sass/selector_parser'
|
26
125
|
|
27
126
|
require 'hexp/h'
|
127
|
+
|
128
|
+
require 'hexp/builder'
|