wrong 0.1.0 → 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/README.markdown +114 -25
- data/lib/predicated/Gemfile +15 -0
- data/lib/predicated/LICENSE +20 -0
- data/lib/predicated/README.markdown +191 -0
- data/lib/predicated/Rakefile +51 -0
- data/lib/predicated/lib/predicated.rb +4 -0
- data/lib/predicated/lib/predicated/autogen_call.rb +37 -0
- data/lib/predicated/lib/predicated/constrain.rb +66 -0
- data/lib/predicated/lib/predicated/evaluate.rb +94 -0
- data/lib/predicated/lib/predicated/from/callable_object.rb +108 -0
- data/lib/predicated/lib/predicated/from/json.rb +59 -0
- data/lib/predicated/lib/predicated/from/ruby_code_string.rb +73 -0
- data/lib/predicated/lib/predicated/from/url_part.rb +104 -0
- data/lib/predicated/lib/predicated/from/xml.rb +61 -0
- data/lib/predicated/lib/predicated/gem_check.rb +34 -0
- data/lib/predicated/lib/predicated/predicate.rb +111 -0
- data/lib/predicated/lib/predicated/print.rb +62 -0
- data/lib/predicated/lib/predicated/selectable.rb +102 -0
- data/lib/predicated/lib/predicated/simple_templated_predicate.rb +79 -0
- data/lib/predicated/lib/predicated/string_utils.rb +20 -0
- data/lib/predicated/lib/predicated/to/arel.rb +41 -0
- data/lib/predicated/lib/predicated/to/json.rb +48 -0
- data/lib/predicated/lib/predicated/to/sentence.rb +94 -0
- data/lib/predicated/lib/predicated/to/solr.rb +15 -0
- data/lib/predicated/lib/predicated/to/xml.rb +67 -0
- data/lib/predicated/lib/predicated/version.rb +3 -0
- data/lib/predicated/predicated.gemspec +22 -0
- data/lib/predicated/test/autogen_call_test.rb +40 -0
- data/lib/predicated/test/canonical_transform_cases.rb +63 -0
- data/lib/predicated/test/constrain_test.rb +86 -0
- data/lib/predicated/test/enumerable_test.rb +32 -0
- data/lib/predicated/test/equality_test.rb +32 -0
- data/lib/predicated/test/evaluate_test.rb +149 -0
- data/lib/predicated/test/from/callable_object_canonical_test.rb +43 -0
- data/lib/predicated/test/from/callable_object_test.rb +78 -0
- data/lib/predicated/test/from/json_test.rb +83 -0
- data/lib/predicated/test/from/ruby_code_string_canonical_test.rb +37 -0
- data/lib/predicated/test/from/ruby_code_string_test.rb +103 -0
- data/lib/predicated/test/from/url_part_parser_test.rb +123 -0
- data/lib/predicated/test/from/url_part_test.rb +48 -0
- data/lib/predicated/test/from/xml_test.rb +57 -0
- data/lib/predicated/test/json_conversion_test.rb +33 -0
- data/lib/predicated/test/print_test.rb +66 -0
- data/lib/predicated/test/selectable_test.rb +123 -0
- data/lib/predicated/test/simple_templated_predicate_test.rb +39 -0
- data/lib/predicated/test/suite.rb +2 -0
- data/lib/predicated/test/test_helper.rb +64 -0
- data/lib/predicated/test/test_helper_with_wrong.rb +6 -0
- data/lib/predicated/test/to/arel_test.rb +85 -0
- data/lib/predicated/test/to/json_test.rb +74 -0
- data/lib/predicated/test/to/sentence_test.rb +90 -0
- data/lib/predicated/test/to/solr_test.rb +39 -0
- data/lib/predicated/test/to/xml_test.rb +72 -0
- data/lib/predicated/test/xml_conversion_test.rb +34 -0
- data/lib/predicated/test_integration/arel_integration_test.rb +52 -0
- data/lib/predicated/test_integration/canonical_integration_cases.rb +66 -0
- data/lib/predicated/test_integration/schema.xml +83 -0
- data/lib/predicated/test_integration/solr_integration_test.rb +71 -0
- data/lib/predicated/test_integration/sqlite_db +0 -0
- data/lib/predicated/test_integration/suite.rb +2 -0
- data/lib/predicated/test_integration/usage_test.rb +252 -0
- data/lib/wrong.rb +3 -1
- data/lib/wrong/adapters/test_unit.rb +1 -3
- data/lib/wrong/assert.rb +81 -24
- data/lib/wrong/chunk.rb +145 -0
- data/lib/wrong/message/string_diff.rb +2 -4
- data/lib/wrong/message/test_context.rb +2 -2
- data/lib/wrong/version.rb +2 -2
- data/test/adapters/minitest_test.rb +16 -9
- data/test/adapters/test_unit_test.rb +1 -1
- data/test/assert_test.rb +90 -0
- data/test/catch_raise_test.rb +2 -2
- data/test/chunk_test.rb +236 -0
- data/test/failures_test.rb +109 -74
- data/test/message/array_diff_test.rb +35 -19
- data/test/message/string_diff_test.rb +39 -15
- data/test/message/test_context_text.rb +2 -2
- data/test/test_helper.rb +25 -7
- metadata +86 -33
- data/test/basic_assert_test.rb +0 -38
@@ -0,0 +1,104 @@
|
|
1
|
+
require "predicated/predicate"
|
2
|
+
|
3
|
+
module Predicated
|
4
|
+
|
5
|
+
require_gem_version("treetop", "1.4.8")
|
6
|
+
|
7
|
+
class Predicate
|
8
|
+
def self.from_url_part(url_part)
|
9
|
+
TreetopUrlPartParser.new.parse(url_part).to_predicate
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module TreetopUrlPart
|
14
|
+
Treetop.load_from_string(%{
|
15
|
+
|
16
|
+
grammar TreetopUrlPart
|
17
|
+
|
18
|
+
include Predicated::TreetopUrlPart
|
19
|
+
|
20
|
+
rule or
|
21
|
+
( and "|" or <OrNode>) / and
|
22
|
+
end
|
23
|
+
|
24
|
+
rule and
|
25
|
+
( leaf "&" and <AndNode> ) / leaf
|
26
|
+
end
|
27
|
+
|
28
|
+
rule operation
|
29
|
+
unquoted_string sign unquoted_string <OperationNode>
|
30
|
+
end
|
31
|
+
|
32
|
+
rule parens
|
33
|
+
not? "(" or ")" <ParensNode>
|
34
|
+
end
|
35
|
+
|
36
|
+
rule not
|
37
|
+
'!'
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
rule leaf
|
43
|
+
operation / parens
|
44
|
+
end
|
45
|
+
|
46
|
+
rule unquoted_string
|
47
|
+
[0-9a-zA-Z]*
|
48
|
+
end
|
49
|
+
|
50
|
+
rule sign
|
51
|
+
('>=' / '<=' / '<' / '>' / '=' )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
})
|
56
|
+
|
57
|
+
class OperationNode < Treetop::Runtime::SyntaxNode
|
58
|
+
def left_text; elements[0].text_value end
|
59
|
+
def sign_text; elements[1].text_value end
|
60
|
+
def right_text; elements[2].text_value end
|
61
|
+
|
62
|
+
SIGN_TO_PREDICATE_CLASS = {
|
63
|
+
"=" => Equal,
|
64
|
+
">" => GreaterThan,
|
65
|
+
"<" => LessThan,
|
66
|
+
">=" => GreaterThanOrEqualTo,
|
67
|
+
"<=" => LessThanOrEqualTo
|
68
|
+
}
|
69
|
+
|
70
|
+
def to_predicate
|
71
|
+
SIGN_TO_PREDICATE_CLASS[sign_text].new(left_text, right_text)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class AndNode < Treetop::Runtime::SyntaxNode
|
76
|
+
def left; elements[0] end
|
77
|
+
def right; elements[2] end
|
78
|
+
|
79
|
+
def to_predicate
|
80
|
+
And.new(left.to_predicate, right.to_predicate)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class OrNode < Treetop::Runtime::SyntaxNode
|
85
|
+
def left; elements[0] end
|
86
|
+
def right; elements[2] end
|
87
|
+
|
88
|
+
def to_predicate
|
89
|
+
Or.new(left.to_predicate, right.to_predicate)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class ParensNode < Treetop::Runtime::SyntaxNode
|
94
|
+
def inner; elements[2] end
|
95
|
+
def not?; elements[0].text_value=="!" end
|
96
|
+
|
97
|
+
def to_predicate
|
98
|
+
inner_predicate = inner.to_predicate
|
99
|
+
not? ? Not.new(inner_predicate) : inner_predicate
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "predicated/predicate"
|
2
|
+
|
3
|
+
module Predicated
|
4
|
+
|
5
|
+
require_gem_version("nokogiri", "1.4.3")
|
6
|
+
|
7
|
+
class Predicate
|
8
|
+
def self.from_xml(xml_str)
|
9
|
+
NodeToPredicate.convert(Nokogiri::XML(xml_str).root)
|
10
|
+
end
|
11
|
+
|
12
|
+
module NodeToPredicate
|
13
|
+
OPERATION_TAG_TO_CLASS = {
|
14
|
+
"equal" => Equal,
|
15
|
+
"greaterThan" => GreaterThan,
|
16
|
+
"lessThan" => LessThan,
|
17
|
+
"greaterThanOrEqualTo" => GreaterThanOrEqualTo,
|
18
|
+
"lessThanOrEqualTo" => LessThanOrEqualTo
|
19
|
+
}
|
20
|
+
|
21
|
+
def self.convert(node)
|
22
|
+
|
23
|
+
node = next_non_text_node(node)
|
24
|
+
|
25
|
+
if node.name == "and"
|
26
|
+
left = next_non_text_node(node.children[0])
|
27
|
+
right = next_non_text_node(left.next)
|
28
|
+
And.new(convert(left), convert(right))
|
29
|
+
elsif node.name == "or"
|
30
|
+
left = next_non_text_node(node.children[0])
|
31
|
+
right = next_non_text_node(left.next)
|
32
|
+
Or.new(convert(left), convert(right))
|
33
|
+
elsif node.name == "not"
|
34
|
+
inner = next_non_text_node(node.children[0])
|
35
|
+
Not.new(convert(inner))
|
36
|
+
elsif operation_class=OPERATION_TAG_TO_CLASS[node.name]
|
37
|
+
left = next_non_text_node(node.children[0])
|
38
|
+
right = next_non_text_node(left.next)
|
39
|
+
operation_class.new(left.text, right.text)
|
40
|
+
else
|
41
|
+
raise DontKnowWhatToDoWithThisXmlTag.new(node.name)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.next_non_text_node(node)
|
46
|
+
while node.text?
|
47
|
+
node = node.next
|
48
|
+
end
|
49
|
+
node
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class DontKnowWhatToDoWithThisXmlTag < StandardError
|
55
|
+
def initialize(xml_tag)
|
56
|
+
super("don't know what to do with #{xml_tag}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Predicated
|
2
|
+
def self.require_gem_version(gem_name, minimum_version, require_name=gem_name)
|
3
|
+
unless Gem.available?(gem_name, Gem::Requirement.create(">= #{minimum_version}"))
|
4
|
+
raise %{
|
5
|
+
Gem: #{gem_name} >=#{minimum_version}
|
6
|
+
Does not appear to be installed. Please install it.
|
7
|
+
|
8
|
+
Predicated is built in a way that allows you to pick and
|
9
|
+
choose which features to use.
|
10
|
+
|
11
|
+
RubyGems has no way to specify optional dependencies,
|
12
|
+
therefore I've made the decision not to have Predicated
|
13
|
+
automatically depend into the various gems referenced
|
14
|
+
in from/to "extensions".
|
15
|
+
|
16
|
+
The cost here is that the gem install doesn't necessarily
|
17
|
+
"just work" for you out of the box. But in return you get
|
18
|
+
greater flexibility.
|
19
|
+
|
20
|
+
Notably, rails/arel unfortunately has a hard dependency
|
21
|
+
on Rails 3 activesupport, which requires ruby 1.8.7.
|
22
|
+
By making from/to dependencies optional, those with
|
23
|
+
no interest in arel can use Predicated in a wider
|
24
|
+
variety of environments.
|
25
|
+
|
26
|
+
For more discussion see:
|
27
|
+
http://stackoverflow.com/questions/2993335/rubygems-optional-dependencies
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
require require_name
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "predicated/gem_check"
|
2
|
+
|
3
|
+
module Predicated
|
4
|
+
|
5
|
+
def Predicate(&block)
|
6
|
+
result = nil
|
7
|
+
Module.new do
|
8
|
+
extend Shorthand
|
9
|
+
result = instance_eval(&block)
|
10
|
+
end
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
class Predicate; end #marker class
|
15
|
+
|
16
|
+
class Unary < Predicate
|
17
|
+
attr_accessor :inner
|
18
|
+
|
19
|
+
def initialize(inner)
|
20
|
+
@inner = inner
|
21
|
+
end
|
22
|
+
|
23
|
+
module FlipThroughMe
|
24
|
+
def each(ancestors=[], &block)
|
25
|
+
yield([self, ancestors])
|
26
|
+
ancestors_including_me = ancestors.dup + [self]
|
27
|
+
inner.each(ancestors_including_me) { |item| block.call(item) } if inner.is_a?(Enumerable)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
include FlipThroughMe
|
31
|
+
include Enumerable
|
32
|
+
|
33
|
+
module ValueEquality
|
34
|
+
def ==(other)
|
35
|
+
self.class == other.class &&
|
36
|
+
self.inner == other.inner
|
37
|
+
end
|
38
|
+
end
|
39
|
+
include ValueEquality
|
40
|
+
end
|
41
|
+
|
42
|
+
class Binary < Predicate
|
43
|
+
attr_accessor :left, :right
|
44
|
+
|
45
|
+
def initialize(left, right)
|
46
|
+
@left = left
|
47
|
+
@right = right
|
48
|
+
end
|
49
|
+
|
50
|
+
module FlipThroughMe
|
51
|
+
def each(ancestors=[], &block)
|
52
|
+
yield([self, ancestors])
|
53
|
+
ancestors_including_me = ancestors.dup + [self]
|
54
|
+
enumerate_side(@left, ancestors_including_me, &block)
|
55
|
+
enumerate_side(@right, ancestors_including_me, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def enumerate_side(thing, ancestors)
|
60
|
+
thing.each(ancestors) { |item| yield(item) } if thing.is_a?(Enumerable)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
include FlipThroughMe
|
64
|
+
include Enumerable
|
65
|
+
|
66
|
+
module ValueEquality
|
67
|
+
def ==(other)
|
68
|
+
self.class == other.class &&
|
69
|
+
self.left == other.left &&
|
70
|
+
self.right == other.right
|
71
|
+
end
|
72
|
+
end
|
73
|
+
include ValueEquality
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
class And < Binary; def self.shorthand; :And end end
|
80
|
+
class Or < Binary; def self.shorthand; :Or end end
|
81
|
+
class Not < Unary; def self.shorthand; :Not end end
|
82
|
+
|
83
|
+
|
84
|
+
class Operation < Binary; end
|
85
|
+
|
86
|
+
class Equal < Operation; def self.shorthand; :Eq end end
|
87
|
+
class LessThan < Operation; def self.shorthand; :Lt end end
|
88
|
+
class GreaterThan < Operation; def self.shorthand; :Gt end end
|
89
|
+
class GreaterThanOrEqualTo < Operation; def self.shorthand; :Gte end end
|
90
|
+
class LessThanOrEqualTo < Operation; def self.shorthand; :Lte end end
|
91
|
+
|
92
|
+
|
93
|
+
module Shorthand
|
94
|
+
def And(left, right) ::Predicated::And.new(left, right) end
|
95
|
+
def Or(left, right) ::Predicated::Or.new(left, right) end
|
96
|
+
def Not(inner) ::Predicated::Not.new(inner) end
|
97
|
+
|
98
|
+
def Eq(left, right) ::Predicated::Equal.new(left, right) end
|
99
|
+
def Lt(left, right) ::Predicated::LessThan.new(left, right) end
|
100
|
+
def Gt(left, right) ::Predicated::GreaterThan.new(left, right) end
|
101
|
+
def Lte(left, right) ::Predicated::LessThanOrEqualTo.new(left, right) end
|
102
|
+
def Gte(left, right) ::Predicated::GreaterThanOrEqualTo.new(left, right) end
|
103
|
+
end
|
104
|
+
|
105
|
+
ALL_PREDICATE_CLASSES = [
|
106
|
+
And, Or, Not,
|
107
|
+
Equal, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo
|
108
|
+
]
|
109
|
+
end
|
110
|
+
|
111
|
+
require "predicated/print"
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Predicated
|
2
|
+
module PrintSupport
|
3
|
+
def inspect(indent="")
|
4
|
+
indent + to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
def part_to_s(thing)
|
9
|
+
part_to_str(thing) {|thing| thing.to_s}
|
10
|
+
end
|
11
|
+
|
12
|
+
def part_inspect(thing, indent="")
|
13
|
+
part_to_str(thing, indent) {|thing| thing.inspect(indent)}
|
14
|
+
end
|
15
|
+
|
16
|
+
def part_to_str(thing, indent="")
|
17
|
+
if thing.is_a?(String)
|
18
|
+
"'#{thing}'"
|
19
|
+
elsif thing.is_a?(Numeric) || thing.is_a?(TrueClass) || thing.is_a?(FalseClass)
|
20
|
+
thing.to_s
|
21
|
+
elsif thing.is_a?(Binary)
|
22
|
+
yield(thing)
|
23
|
+
elsif thing.nil?
|
24
|
+
"nil"
|
25
|
+
else
|
26
|
+
"#{thing.class.name}{'#{thing.to_s}'}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Unary < Predicate
|
32
|
+
include PrintSupport
|
33
|
+
def to_s
|
34
|
+
"#{self.class.shorthand}(#{part_to_s(inner)})"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Binary < Predicate
|
39
|
+
include PrintSupport
|
40
|
+
def to_s
|
41
|
+
"#{self.class.shorthand}(#{part_to_s(left)},#{part_to_s(right)})"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module ContainerToString
|
46
|
+
def inspect(indent="")
|
47
|
+
next_indent = indent + " " + " "
|
48
|
+
|
49
|
+
str = "#{indent}#{self.class.shorthand}(\n"
|
50
|
+
str << "#{part_inspect(left, next_indent)},\n"
|
51
|
+
str << "#{part_inspect(right, next_indent)}\n"
|
52
|
+
str << "#{indent})"
|
53
|
+
str << "\n" if indent == ""
|
54
|
+
|
55
|
+
str
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class And; include ContainerToString end
|
60
|
+
class Or; include ContainerToString end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
|
2
|
+
class Object
|
3
|
+
# todo: make this definition conditional
|
4
|
+
# todo: move this to a monkey patch file
|
5
|
+
def singleton_class
|
6
|
+
class << self
|
7
|
+
self
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Predicated
|
13
|
+
module Selectable
|
14
|
+
# Make an Enumerable instance into a Selectable.
|
15
|
+
# This does for instances what "include Selectable" does for classes.
|
16
|
+
# todo: rename?
|
17
|
+
def self.bless_enumerable(enumerable, selectors)
|
18
|
+
enumerable.singleton_class.instance_eval do
|
19
|
+
include Selectable
|
20
|
+
selector selectors
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# merge several hashes into one, skipping nils
|
25
|
+
# todo: unit test
|
26
|
+
# todo: move onto Hash?
|
27
|
+
def self.merge_many(*hashes)
|
28
|
+
result = {}
|
29
|
+
hashes.compact.each do |hash|
|
30
|
+
result.merge! hash
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
SELECTORS = :@_predicated_selectors
|
36
|
+
|
37
|
+
def self.included(base)
|
38
|
+
base.extend ClassMethods
|
39
|
+
end
|
40
|
+
|
41
|
+
module ClassMethods
|
42
|
+
def selector(hash)
|
43
|
+
instance_variable_set(SELECTORS, Selectable.merge_many(instance_variable_get(SELECTORS), hash))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def selectors
|
48
|
+
class_selectors = self.class.instance_variable_get(SELECTORS)
|
49
|
+
singleton_selectors = self.singleton_class.instance_variable_get(SELECTORS)
|
50
|
+
instance_selectors = self.instance_variable_get(SELECTORS)
|
51
|
+
Selectable.merge_many(class_selectors, singleton_selectors, instance_selectors)
|
52
|
+
end
|
53
|
+
|
54
|
+
def select(*keys, &block)
|
55
|
+
if block_given?
|
56
|
+
super
|
57
|
+
else
|
58
|
+
key = keys.shift
|
59
|
+
result =
|
60
|
+
if key
|
61
|
+
selecting_proc = selectors[key]
|
62
|
+
raise "no selector found for '#{key}'. current selectors: [#{selectors.collect { |k, v| k.to_s }.join(",")}]" unless selecting_proc
|
63
|
+
memos_for(:select)[key] ||= begin
|
64
|
+
super(&selecting_proc)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
raise "select must be called with either a key or a block"
|
68
|
+
end
|
69
|
+
|
70
|
+
Selectable.bless_enumerable(result, selectors)
|
71
|
+
|
72
|
+
if keys.length >= 1
|
73
|
+
result.select(*keys, &block)
|
74
|
+
else
|
75
|
+
result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def memos_for(group)
|
82
|
+
@_predicated_memos ||= {}
|
83
|
+
@_predicated_memos[group] ||= {}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
all_basic_selectors = {:all => proc{|predicate, enumerable|true}}.merge(
|
88
|
+
([Unary, Binary, Operation] + ALL_PREDICATE_CLASSES).inject({}) do |h, klass|
|
89
|
+
h[klass] = proc{|predicate, enumerable|predicate.is_a?(klass)}
|
90
|
+
h
|
91
|
+
end
|
92
|
+
)
|
93
|
+
|
94
|
+
ALL_PREDICATE_CLASSES.each do |klass|
|
95
|
+
klass.class_eval do
|
96
|
+
klass.send(:include, Selectable)
|
97
|
+
klass.selector all_basic_selectors
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|