hexp 0.0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|