elementor 0.0.4 → 0.0.5
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/lib/core_ext/array.rb +5 -0
- data/lib/core_ext/kernel.rb +9 -3
- data/lib/core_ext/object.rb +0 -4
- data/lib/elementor.rb +2 -3
- data/lib/elementor/element_set.rb +24 -11
- data/lib/elementor/result.rb +65 -31
- data/lib/elementor/spec.rb +4 -0
- metadata +3 -2
data/lib/core_ext/kernel.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
module Kernel
|
2
|
-
def blank_context(
|
2
|
+
def blank_context(*args, &block)
|
3
|
+
ivars = args.extract_options!
|
4
|
+
|
5
|
+
args.push(/(^__)|instance_/)
|
6
|
+
|
3
7
|
klass = Class.new do
|
4
|
-
instance_methods.each
|
8
|
+
instance_methods.each do |m|
|
9
|
+
undef_method(m) unless args.any? { |pattern| m =~ pattern }
|
10
|
+
end
|
5
11
|
end
|
6
12
|
|
7
|
-
klass.class_eval(&block)
|
13
|
+
klass.class_eval(&block) if block_given?
|
8
14
|
instance = klass.new
|
9
15
|
ivars.each { |key, value| instance.instance_variable_set("@#{key}", value) }
|
10
16
|
instance
|
data/lib/core_ext/object.rb
CHANGED
data/lib/elementor.rb
CHANGED
@@ -3,6 +3,7 @@ $LOAD_PATH << File.dirname(__FILE__) + '/elementor'
|
|
3
3
|
|
4
4
|
require 'rubygems'
|
5
5
|
require 'nokogiri'
|
6
|
+
require 'array'
|
6
7
|
require 'kernel'
|
7
8
|
require 'object'
|
8
9
|
require 'symbol'
|
@@ -11,8 +12,6 @@ require 'element_set'
|
|
11
12
|
|
12
13
|
module Elementor
|
13
14
|
def elements(opts={}, &block)
|
14
|
-
|
15
|
-
namer.define_elements!
|
16
|
-
namer.dispatcher
|
15
|
+
Result.new(self, opts, &block).dispatcher
|
17
16
|
end
|
18
17
|
end
|
@@ -1,41 +1,54 @@
|
|
1
1
|
module Elementor
|
2
|
+
# ElementSet objects wrap a Nokogiri #search result and
|
3
|
+
# add additional functionality such as chained filtering.
|
2
4
|
class ElementSet < Array
|
3
5
|
attr_accessor :result, :selector
|
4
6
|
|
7
|
+
# A simple filter for selecting only elements with content
|
8
|
+
# that either includes a String passed in, or matches a Regexp.
|
5
9
|
def with_text(matcher)
|
6
|
-
|
10
|
+
filter do |item|
|
7
11
|
case matcher
|
8
12
|
when Regexp then item.text =~ matcher
|
9
13
|
when String then item.text.include?(matcher)
|
14
|
+
else item.text.include?(matcher.to_s)
|
10
15
|
end
|
11
|
-
|
16
|
+
end
|
12
17
|
end
|
13
18
|
|
19
|
+
alias_method :text, :with_text
|
20
|
+
|
21
|
+
# Attribute filtering using hashes. See the specs for examples.
|
14
22
|
def with_attrs(options={})
|
15
|
-
|
16
|
-
options.all?
|
23
|
+
filter do |item|
|
24
|
+
options.all? do |key, value|
|
17
25
|
case value
|
18
26
|
when Regexp then item[key.to_s] =~ value
|
19
27
|
when String then item[key.to_s] == value
|
28
|
+
else item[key.to_s] == value.to_s
|
20
29
|
end
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def inspect
|
26
|
-
map(&:text).inspect
|
30
|
+
end
|
31
|
+
end
|
27
32
|
end
|
28
33
|
|
34
|
+
alias_method :attrs, :with_attrs
|
35
|
+
|
29
36
|
def method_missing(sym, *args, &block)
|
30
|
-
result.
|
37
|
+
result.respond_to?(sym) ? result.send(sym, doc, *args) : super
|
31
38
|
end
|
32
39
|
|
33
40
|
def respond_to?(sym)
|
34
41
|
result.respond_to?(sym) || super
|
35
42
|
end
|
36
43
|
|
44
|
+
private
|
45
|
+
|
37
46
|
def doc
|
38
47
|
result.doc.search(selector)
|
39
48
|
end
|
49
|
+
|
50
|
+
def filter(&block)
|
51
|
+
replace(select(&block)) ; return self
|
52
|
+
end
|
40
53
|
end
|
41
54
|
end
|
data/lib/elementor/result.rb
CHANGED
@@ -8,63 +8,97 @@ module Elementor
|
|
8
8
|
@context = context
|
9
9
|
@doc_ready = false
|
10
10
|
block.call(naming_context)
|
11
|
+
define_elements!
|
11
12
|
end
|
12
13
|
|
14
|
+
# Allows for the parsing of raw markup that doesn't come
|
15
|
+
# from the :from option.
|
13
16
|
def parse!(markup)
|
14
17
|
doc(markup)
|
15
18
|
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
# Returns a blank slate object that delegates to either an
|
21
|
+
# instance of Result or the original Nokogiri doc.
|
22
|
+
def dispatcher
|
23
|
+
@dispatcher ||= blank_context(:this => self) do
|
24
|
+
def method_missing(sym, *args, &block)
|
25
|
+
@this.doc_ready!
|
26
|
+
[@this, @this.doc].each do |context|
|
27
|
+
next unless context.respond_to?(sym)
|
28
|
+
return context.send(sym, *args, &block)
|
29
|
+
end
|
30
|
+
super # raise NoMethodError if no context can handle
|
21
31
|
end
|
22
32
|
end
|
23
33
|
end
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
35
|
+
# The list of name/selector pairs you specify in the
|
36
|
+
# elements block.
|
37
|
+
def element_names
|
38
|
+
@element_names ||= { }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the raw Nokogiri doc once a method has been called
|
42
|
+
# on the dispatcher. Up until that point, returns nil.
|
43
|
+
def doc(markup=nil)
|
44
|
+
if html = markup || content
|
45
|
+
@doc = nil if markup
|
46
|
+
@doc ||= Nokogiri(html)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Indicates whether or not the dispatcher has received messages,
|
51
|
+
# meaning the content method can be called.
|
52
|
+
def doc_ready?
|
53
|
+
@doc_ready
|
54
|
+
end
|
55
|
+
|
56
|
+
def doc_ready!
|
57
|
+
@doc_ready = true
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Blank slate context for defining element names.
|
63
|
+
def naming_context
|
64
|
+
@naming_context ||= blank_context(:this => self) do
|
65
|
+
def method_missing(sym, *args)
|
66
|
+
@this.element_names[sym] = *args
|
30
67
|
end
|
31
68
|
end
|
32
69
|
end
|
33
|
-
|
70
|
+
|
71
|
+
# Takes element names and defines methods that return ElementSet
|
72
|
+
# objects with can be chained and filtered.
|
34
73
|
def define_elements!
|
35
74
|
element_names.each do |name, selector|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
75
|
+
metaclass.class_eval(<<-END, __FILE__, __LINE__)
|
76
|
+
def #{name}(*filters, &block)
|
77
|
+
make_element_set(#{name.inspect}, #{selector.inspect}, *filters, &block)
|
78
|
+
end
|
79
|
+
END
|
42
80
|
end
|
43
81
|
end
|
44
82
|
|
83
|
+
def make_element_set(name, selector, *filters, &block)
|
84
|
+
set = ElementSet.new scope(filters).search(selector)
|
85
|
+
set.result = self
|
86
|
+
set.selector = selector
|
87
|
+
set = filters.empty? ? set : filters.inject(set) { |result, fn| fn[result] }
|
88
|
+
set = block.call(set) if block_given?
|
89
|
+
set
|
90
|
+
end
|
91
|
+
|
92
|
+
# Enables the chaining of element selector methods to only search
|
93
|
+
# within the scope of a certain ElementSet.
|
45
94
|
def scope(filters)
|
46
95
|
scope = filters.first.is_a?(Proc) ? nil : filters.shift
|
47
96
|
scope || doc
|
48
97
|
end
|
49
98
|
|
50
|
-
def element_names
|
51
|
-
@element_names ||= { }
|
52
|
-
end
|
53
|
-
|
54
|
-
def doc(markup=nil)
|
55
|
-
if html = markup || content
|
56
|
-
@doc = nil if markup
|
57
|
-
@doc ||= Nokogiri(html)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
99
|
def content
|
62
100
|
return unless doc_ready?
|
63
101
|
@content ||= context.send(opts[:from] || :body)
|
64
102
|
end
|
65
|
-
|
66
|
-
def doc_ready?
|
67
|
-
@doc_ready
|
68
|
-
end
|
69
103
|
end
|
70
104
|
end
|
data/lib/elementor/spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elementor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pat Nakajima
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- lib/elementor/element_set.rb
|
38
38
|
- lib/elementor/result.rb
|
39
39
|
- lib/core_ext
|
40
|
+
- lib/core_ext/array.rb
|
40
41
|
- lib/core_ext/object.rb
|
41
42
|
- lib/core_ext/kernel.rb
|
42
43
|
- lib/core_ext/symbol.rb
|
@@ -62,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
63
|
requirements: []
|
63
64
|
|
64
65
|
rubyforge_project:
|
65
|
-
rubygems_version: 1.3.
|
66
|
+
rubygems_version: 1.3.1
|
66
67
|
signing_key:
|
67
68
|
specification_version: 2
|
68
69
|
summary: Prettier element traversal with Nokogiri
|