wrong 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/README.markdown +114 -25
  2. data/lib/predicated/Gemfile +15 -0
  3. data/lib/predicated/LICENSE +20 -0
  4. data/lib/predicated/README.markdown +191 -0
  5. data/lib/predicated/Rakefile +51 -0
  6. data/lib/predicated/lib/predicated.rb +4 -0
  7. data/lib/predicated/lib/predicated/autogen_call.rb +37 -0
  8. data/lib/predicated/lib/predicated/constrain.rb +66 -0
  9. data/lib/predicated/lib/predicated/evaluate.rb +94 -0
  10. data/lib/predicated/lib/predicated/from/callable_object.rb +108 -0
  11. data/lib/predicated/lib/predicated/from/json.rb +59 -0
  12. data/lib/predicated/lib/predicated/from/ruby_code_string.rb +73 -0
  13. data/lib/predicated/lib/predicated/from/url_part.rb +104 -0
  14. data/lib/predicated/lib/predicated/from/xml.rb +61 -0
  15. data/lib/predicated/lib/predicated/gem_check.rb +34 -0
  16. data/lib/predicated/lib/predicated/predicate.rb +111 -0
  17. data/lib/predicated/lib/predicated/print.rb +62 -0
  18. data/lib/predicated/lib/predicated/selectable.rb +102 -0
  19. data/lib/predicated/lib/predicated/simple_templated_predicate.rb +79 -0
  20. data/lib/predicated/lib/predicated/string_utils.rb +20 -0
  21. data/lib/predicated/lib/predicated/to/arel.rb +41 -0
  22. data/lib/predicated/lib/predicated/to/json.rb +48 -0
  23. data/lib/predicated/lib/predicated/to/sentence.rb +94 -0
  24. data/lib/predicated/lib/predicated/to/solr.rb +15 -0
  25. data/lib/predicated/lib/predicated/to/xml.rb +67 -0
  26. data/lib/predicated/lib/predicated/version.rb +3 -0
  27. data/lib/predicated/predicated.gemspec +22 -0
  28. data/lib/predicated/test/autogen_call_test.rb +40 -0
  29. data/lib/predicated/test/canonical_transform_cases.rb +63 -0
  30. data/lib/predicated/test/constrain_test.rb +86 -0
  31. data/lib/predicated/test/enumerable_test.rb +32 -0
  32. data/lib/predicated/test/equality_test.rb +32 -0
  33. data/lib/predicated/test/evaluate_test.rb +149 -0
  34. data/lib/predicated/test/from/callable_object_canonical_test.rb +43 -0
  35. data/lib/predicated/test/from/callable_object_test.rb +78 -0
  36. data/lib/predicated/test/from/json_test.rb +83 -0
  37. data/lib/predicated/test/from/ruby_code_string_canonical_test.rb +37 -0
  38. data/lib/predicated/test/from/ruby_code_string_test.rb +103 -0
  39. data/lib/predicated/test/from/url_part_parser_test.rb +123 -0
  40. data/lib/predicated/test/from/url_part_test.rb +48 -0
  41. data/lib/predicated/test/from/xml_test.rb +57 -0
  42. data/lib/predicated/test/json_conversion_test.rb +33 -0
  43. data/lib/predicated/test/print_test.rb +66 -0
  44. data/lib/predicated/test/selectable_test.rb +123 -0
  45. data/lib/predicated/test/simple_templated_predicate_test.rb +39 -0
  46. data/lib/predicated/test/suite.rb +2 -0
  47. data/lib/predicated/test/test_helper.rb +64 -0
  48. data/lib/predicated/test/test_helper_with_wrong.rb +6 -0
  49. data/lib/predicated/test/to/arel_test.rb +85 -0
  50. data/lib/predicated/test/to/json_test.rb +74 -0
  51. data/lib/predicated/test/to/sentence_test.rb +90 -0
  52. data/lib/predicated/test/to/solr_test.rb +39 -0
  53. data/lib/predicated/test/to/xml_test.rb +72 -0
  54. data/lib/predicated/test/xml_conversion_test.rb +34 -0
  55. data/lib/predicated/test_integration/arel_integration_test.rb +52 -0
  56. data/lib/predicated/test_integration/canonical_integration_cases.rb +66 -0
  57. data/lib/predicated/test_integration/schema.xml +83 -0
  58. data/lib/predicated/test_integration/solr_integration_test.rb +71 -0
  59. data/lib/predicated/test_integration/sqlite_db +0 -0
  60. data/lib/predicated/test_integration/suite.rb +2 -0
  61. data/lib/predicated/test_integration/usage_test.rb +252 -0
  62. data/lib/wrong.rb +3 -1
  63. data/lib/wrong/adapters/test_unit.rb +1 -3
  64. data/lib/wrong/assert.rb +81 -24
  65. data/lib/wrong/chunk.rb +145 -0
  66. data/lib/wrong/message/string_diff.rb +2 -4
  67. data/lib/wrong/message/test_context.rb +2 -2
  68. data/lib/wrong/version.rb +2 -2
  69. data/test/adapters/minitest_test.rb +16 -9
  70. data/test/adapters/test_unit_test.rb +1 -1
  71. data/test/assert_test.rb +90 -0
  72. data/test/catch_raise_test.rb +2 -2
  73. data/test/chunk_test.rb +236 -0
  74. data/test/failures_test.rb +109 -74
  75. data/test/message/array_diff_test.rb +35 -19
  76. data/test/message/string_diff_test.rb +39 -15
  77. data/test/message/test_context_text.rb +2 -2
  78. data/test/test_helper.rb +25 -7
  79. metadata +86 -33
  80. data/test/basic_assert_test.rb +0 -38
@@ -0,0 +1,79 @@
1
+ require "predicated/predicate"
2
+ require "predicated/evaluate"
3
+
4
+ module Predicated
5
+ def SimpleTemplatedPredicate(&block)
6
+ result = nil
7
+ Module.new do
8
+ extend SimpleTemplatedShorthand
9
+ result = instance_eval(&block)
10
+ end
11
+ result
12
+ end
13
+
14
+ class And
15
+ def fill_in(placeholder_replacement)
16
+ And.new(left.fill_in(placeholder_replacement), right.fill_in(placeholder_replacement))
17
+ end
18
+ end
19
+
20
+ class Or
21
+ def fill_in(placeholder_replacement)
22
+ Or.new(left.fill_in(placeholder_replacement), right.fill_in(placeholder_replacement))
23
+ end
24
+ end
25
+
26
+ class Not
27
+ def fill_in(placeholder_replacement)
28
+ Not.new(inner.fill_in(placeholder_replacement))
29
+ end
30
+ end
31
+
32
+ class Operation
33
+ def fill_in(placeholder_replacement)
34
+ self.class.new(placeholder_replacement, right)
35
+ end
36
+ end
37
+
38
+ class Call
39
+ def fill_in(placeholder_replacement)
40
+ self.class.new(placeholder_replacement, method_sym, right)
41
+ end
42
+ end
43
+
44
+ class Placeholder; end
45
+
46
+ module SimpleTemplatedShorthand
47
+ include Shorthand
48
+
49
+ def Eq(right) ::Predicated::Equal.new(Placeholder, right) end
50
+ def Lt(right) ::Predicated::LessThan.new(Placeholder, right) end
51
+ def Gt(right) ::Predicated::GreaterThan.new(Placeholder, right) end
52
+ def Lte(right) ::Predicated::LessThanOrEqualTo.new(Placeholder, right) end
53
+ def Gte(right) ::Predicated::GreaterThanOrEqualTo.new(Placeholder, right) end
54
+
55
+ def Call(method_sym, right=[]) ::Predicated::Call.new(Placeholder, method_sym, right) end
56
+ end
57
+
58
+ class Operation < Binary
59
+ def to_s
60
+ if left == Placeholder
61
+ "#{self.class.shorthand}(#{part_to_s(right)})"
62
+ else
63
+ super
64
+ end
65
+ end
66
+ end
67
+
68
+ class Call < Operation
69
+ def to_s
70
+ if left == Placeholder
71
+ "Call(#{method_sym.to_s}(#{part_to_s(right)}))"
72
+ else
73
+ super
74
+ end
75
+ end
76
+ end
77
+
78
+
79
+ end
@@ -0,0 +1,20 @@
1
+ module Predicated
2
+ module StringUtils
3
+
4
+ #Ripped from activesupport.
5
+ #If I start using a bunch of code from that project I'll create a dependency.
6
+ #I hope this is not bad form.
7
+ def self.underscore(camel_cased_word)
8
+ camel_cased_word.to_s.gsub(/::/, '/').
9
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
10
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
11
+ tr("-", "_").
12
+ downcase
13
+ end
14
+
15
+ def self.uppercamelize(lower_case_and_underscored_word)
16
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ raise "this doesn't work in 1.8.6 because the arel gem is 1.8.7-only" if RUBY_VERSION=="1.8.6"
2
+
3
+ require "predicated/predicate"
4
+
5
+ module Predicated
6
+
7
+ require_gem_version("arel", "0.4.0")
8
+
9
+ class And
10
+ def to_arel(arel_table)
11
+ Arel::Predicates::And.new(left.to_arel(arel_table), right.to_arel(arel_table))
12
+ end
13
+ end
14
+
15
+ class Or
16
+ def to_arel(arel_table)
17
+ Arel::Predicates::Or.new(left.to_arel(arel_table), right.to_arel(arel_table))
18
+ end
19
+ end
20
+
21
+ class Not
22
+ def to_arel(arel_table)
23
+ Arel::Predicates::Not.new(inner.to_arel(arel_table))
24
+ end
25
+ end
26
+
27
+
28
+ class Operation
29
+ def to_arel(arel_table)
30
+ arel_class.new(arel_table.attributes[left], right)
31
+ end
32
+ end
33
+
34
+ class Equal; def arel_class; Arel::Predicates::Equality end end
35
+ class LessThan; def arel_class; Arel::Predicates::LessThan end end
36
+ class GreaterThan; def arel_class; Arel::Predicates::GreaterThan end end
37
+ class LessThanOrEqualTo; def arel_class; Arel::Predicates::LessThanOrEqualTo end end
38
+ class GreaterThanOrEqualTo; def arel_class; Arel::Predicates::GreaterThanOrEqualTo end end
39
+
40
+
41
+ end
@@ -0,0 +1,48 @@
1
+ require "predicated/predicate"
2
+
3
+ module Predicated
4
+
5
+ require_gem_version("json", "1.1.9")
6
+
7
+ module JsonStructToJsonStr
8
+ def to_json_str
9
+ JSON.pretty_generate(to_json_struct)
10
+ end
11
+ end
12
+
13
+ class And
14
+ include JsonStructToJsonStr
15
+ def to_json_struct
16
+ {"and" => [left.to_json_struct, right.to_json_struct]}
17
+ end
18
+ end
19
+
20
+ class Or
21
+ include JsonStructToJsonStr
22
+ def to_json_struct
23
+ {"or" => [left.to_json_struct, right.to_json_struct]}
24
+ end
25
+ end
26
+
27
+ class Not
28
+ include JsonStructToJsonStr
29
+ def to_json_struct
30
+ {"not" => inner.to_json_struct}
31
+ end
32
+ end
33
+
34
+ class Operation
35
+ include JsonStructToJsonStr
36
+ def to_json_struct
37
+ [left, json_sign, right]
38
+ end
39
+ end
40
+
41
+ class Equal; private; def json_sign; "==" end end
42
+ class LessThan; private; def json_sign; "<" end end
43
+ class GreaterThan; private; def json_sign; ">" end end
44
+ class LessThanOrEqualTo; private; def json_sign; "<=" end end
45
+ class GreaterThanOrEqualTo; private; def json_sign; ">=" end end
46
+
47
+
48
+ end
@@ -0,0 +1,94 @@
1
+ require "predicated/predicate"
2
+ require "predicated/evaluate"
3
+
4
+ module Predicated
5
+
6
+ module ContainerSentence
7
+ def to_sentence
8
+ left.to_sentence + joining_str + right.to_sentence
9
+ end
10
+
11
+ def to_negative_sentence
12
+ "This is not true: " + to_sentence
13
+ end
14
+ end
15
+
16
+ class And; include ContainerSentence; def joining_str; " and " end; end
17
+ class Or; include ContainerSentence; def joining_str; " or " end;end
18
+
19
+ class Not
20
+ def to_sentence
21
+ inner.to_negative_sentence
22
+ end
23
+
24
+ def to_negative_sentence
25
+ inner.to_sentence
26
+ end
27
+ end
28
+
29
+ class Operation
30
+
31
+ def self.register_verb_phrase(method_sym,
32
+ positive_verb_phrase,
33
+ negative_verb_phrase,
34
+ accepts_object=true)
35
+ @@method_sym_to_phrase_info[method_sym] = {
36
+ :positive => positive_verb_phrase,
37
+ :negative => negative_verb_phrase,
38
+ :accepts_object => accepts_object
39
+ }
40
+ end
41
+
42
+ def self.reset_verb_phrases
43
+ @@method_sym_to_phrase_info = {}
44
+
45
+ register_verb_phrase(:==, "is equal to", "is not equal to")
46
+ register_verb_phrase(:>, "is greater than", "is not greater than")
47
+ register_verb_phrase(:<, "is less than", "is not less than")
48
+ register_verb_phrase(:>=, "is greater than or equal to", "is not greater than or equal to")
49
+ register_verb_phrase(:<=, "is less than or equal to", "is not less than or equal to")
50
+
51
+ register_verb_phrase(:include?, "includes", "does not include")
52
+ register_verb_phrase(:is_a?, "is a", "is not a")
53
+ register_verb_phrase(:nil?, "is nil", "is not nil", accepts_object=false)
54
+
55
+ nil
56
+ end
57
+
58
+ reset_verb_phrases
59
+
60
+
61
+ def to_sentence
62
+ sentence(verb_phrase[:positive])
63
+ end
64
+
65
+ def to_negative_sentence
66
+ sentence(verb_phrase[:negative])
67
+ end
68
+
69
+ private
70
+
71
+ def sentence(verb_phrase_str)
72
+ left_str = format_value(left)
73
+ right_str = format_value(right)
74
+
75
+ str = left_str + " " + verb_phrase_str
76
+ str << " " + right_str if verb_phrase[:accepts_object]
77
+ str
78
+ end
79
+
80
+ def verb_phrase
81
+ @@method_sym_to_phrase_info[method_sym] || {
82
+ :positive => "is " + rudimentary=method_sym.to_s.gsub("_", " ").gsub("?", ""),
83
+ :negative => "is not " + rudimentary,
84
+ :accepts_object => true
85
+ }
86
+ end
87
+
88
+ def format_value(value)
89
+ value.inspect
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,15 @@
1
+ require "predicated/predicate"
2
+
3
+ module Predicated
4
+
5
+ class And; def to_solr; "(#{left.to_solr} AND #{right.to_solr})" end end
6
+ class Or; def to_solr; "(#{left.to_solr} OR #{right.to_solr})" end end
7
+ class Not; def to_solr; "NOT(#{inner.to_solr})" end end
8
+
9
+ class Equal; def to_solr; "#{left}:#{right}" end end
10
+ class GreaterThan; def to_solr; "#{left}:[#{(right+1)} TO *]" end end
11
+ class LessThan; def to_solr; "#{left}:[* TO #{(right-1)}]" end end
12
+ class GreaterThanOrEqualTo; def to_solr; "#{left}:[#{right} TO *]" end end
13
+ class LessThanOrEqualTo; def to_solr; "#{left}:[* TO #{right}]" end end
14
+
15
+ end
@@ -0,0 +1,67 @@
1
+ require "predicated/predicate"
2
+
3
+ module Predicated
4
+
5
+ module ContainerToXml
6
+ private
7
+ def to_xml_with_tag_name(indent, tag_name)
8
+ inner = %{\n#{left.to_xml(indent + " ")}\n#{right.to_xml(indent + " ")}}
9
+ "#{indent}<#{tag_name}>#{inner}\n#{indent}</#{tag_name}>"
10
+ end
11
+ end
12
+
13
+ class And
14
+ include ContainerToXml
15
+ def to_xml(indent="")
16
+ to_xml_with_tag_name(indent, "and")
17
+ end
18
+ end
19
+
20
+ class Or
21
+ include ContainerToXml
22
+ def to_xml(indent="")
23
+ to_xml_with_tag_name(indent, "or")
24
+ end
25
+ end
26
+
27
+ class Not
28
+ def to_xml(indent="")
29
+ "#{indent}<not>\n#{inner.to_xml(indent + " ")}\n#{indent}</not>"
30
+ end
31
+ end
32
+
33
+ class Operation
34
+ def to_xml(indent="")
35
+ "#{indent}<#{tag_name}><left>#{escape(left)}</left><right>#{escape(right)}</right></#{tag_name}>"
36
+ end
37
+
38
+ private
39
+
40
+ CONVERSION_TABLE = [
41
+ ['&', '&amp;'],
42
+ ['<', '&lt;'],
43
+ ['>', '&gt;'],
44
+ ["'", '&apos;'],
45
+ ['"', '&quot;']
46
+ ]
47
+
48
+ #it's fast. see http://groups.google.com/group/ruby-talk-google/browse_thread/thread/c0280bab8a037184/9b8ca81c2607189d?hl=en&ie=UTF-8
49
+ def escape(value)
50
+ if value.class == String
51
+ value.gsub(/['"&<>]/) do |match|
52
+ CONVERSION_TABLE.assoc(match).last
53
+ end
54
+ else
55
+ value
56
+ end
57
+ end
58
+ end
59
+
60
+ class Equal; private; def tag_name; "equal" end end
61
+ class LessThan; private; def tag_name; "lessThan" end end
62
+ class GreaterThan; private; def tag_name; "greaterThan" end end
63
+ class LessThanOrEqualTo; private; def tag_name; "lessThanOrEqualTo" end end
64
+ class GreaterThanOrEqualTo; private; def tag_name; "greaterThanOrEqualTo" end end
65
+
66
+
67
+ end
@@ -0,0 +1,3 @@
1
+ module Predicated
2
+ VERSION = "0.1.0" unless defined?(Predicated::VERSION)
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/predicated/version.rb', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "predicated"
6
+ s.version = Predicated::VERSION
7
+ s.authors = ["Steve Conover"]
8
+ s.date = %q{2010-07-06}
9
+ s.email = "sconover@gmail.com"
10
+ s.homepage = "http://github.com/sconover/predicated"
11
+ s.summary = "Predicated is a simple predicate model for Ruby"
12
+ s.description = <<-EOS.strip
13
+ Predicated is a simple predicate model for Ruby.
14
+ EOS
15
+ s.rubyforge_project = "predicated"
16
+
17
+ s.files = Dir['lib/**/*']
18
+ s.test_files = Dir['test/**/*.rb']
19
+
20
+ s.has_rdoc = true
21
+ s.extra_rdoc_files = %w[README.markdown]
22
+ end
@@ -0,0 +1,40 @@
1
+ require "./test/test_helper_with_wrong"
2
+
3
+ require "predicated/simple_templated_predicate"
4
+ require "predicated/autogen_call"
5
+
6
+ include Predicated
7
+
8
+ regarding "if an unknown shorthand method is invoked, assume it's meant to be a Call predicate" do
9
+
10
+ test "generate a call predicate. form is Verb(subject [, object...]) ==> subject.verb_lowercase_underscored([object...])" do
11
+ assert{ Predicate { Include?("abc", "bc") }.evaluate }
12
+ deny { Predicate { Include?("abc", "ZZZ") }.evaluate }
13
+
14
+ assert{ Predicate { Include?("abc", "bc") } == Predicate { AutogenCall.new("abc", :include?, ["bc"]) } }
15
+ assert{ Predicate { Nil?(nil) } == Predicate { AutogenCall.new(nil, :nil?) } }
16
+ end
17
+
18
+ test "existing predicates are unaffected" do
19
+ assert{ Predicate { Eq(1, 1) } == Predicate { Eq(1, 1) } }
20
+ end
21
+
22
+ test "works when nested too" do
23
+ assert{ Predicate { And(Eq(1, 1),Include?("abc", "bc")) } ==
24
+ Predicate { And(Eq(1, 1),AutogenCall.new("abc", :include?, ["bc"])) } }
25
+ end
26
+
27
+ test "looks neato when used with currying" do
28
+ assert{ SimpleTemplatedPredicate{ Or(Nil?,Include?("bc")) }.fill_in("abc") ==
29
+ Predicate { Or(AutogenCall.new("abc", :nil?),AutogenCall.new("abc", :include?, ["bc"])) } }
30
+ end
31
+
32
+ test "to_s, inspect" do
33
+ assert{ Predicate { Include?("abc", "bc") }.to_s == "Include?('abc',('bc'))" }
34
+ assert{ Predicate { Nil?(nil) }.to_s == "Nil?(nil)" }
35
+
36
+ assert{ Predicate { Include?("abc", "bc") }.inspect == "Include?('abc',('bc'))" }
37
+ assert{ Predicate { Nil?(nil) }.inspect == "Nil?(nil)" }
38
+ end
39
+
40
+ end
@@ -0,0 +1,63 @@
1
+ module CanonicalTransformCases
2
+
3
+ module ClassMethods
4
+ def create_canonical_tests(expectations, proper_typing=true)
5
+ val = {
6
+ :one => 1,
7
+ :two => 2,
8
+ :three => 3,
9
+ :true_value => true,
10
+ :false_value => false
11
+ }
12
+
13
+ val.each{|k,v|val[k]=v.to_s} unless proper_typing
14
+
15
+ tests = {
16
+ "simple operations" => {
17
+ "eq" => Predicate{ Eq("a",val[:three]) },
18
+ "gt" => Predicate{ Gt("a",val[:three]) },
19
+ "lt" => Predicate{ Lt("a",val[:three]) },
20
+ "gte" => Predicate{ Gte("a",val[:three]) },
21
+ "lte" => Predicate{ Lte("a",val[:three]) }
22
+ },
23
+ "primitive types" => {
24
+ "true" => Predicate{ Eq("a",val[:true_value]) },
25
+ "false" => Predicate{ Eq("a",val[:false_value]) },
26
+ "string" => Predicate{ Eq("a","yyy") },
27
+ },
28
+ "not" => {
29
+ "simple" => Predicate{ Not(Eq("a",val[:true_value])) }
30
+ },
31
+ "simple and / or" => {
32
+ "and" => Predicate{ And(Eq("a", val[:one]),Eq("b", val[:two])) },
33
+ "or" => Predicate{ Or(Eq("a", val[:one]),Eq("b", val[:two])) }
34
+ },
35
+ "complex and / or" => {
36
+ "or and" => Predicate{ Or(And(Eq("a", val[:one]),Eq("b", val[:two])), Eq("c",val[:three])) }
37
+ }
38
+ }
39
+
40
+ tests.each do |test_name, cases|
41
+ test test_name do
42
+
43
+ not_found =
44
+ cases.keys.sort.select do |case_name|
45
+ expectations[test_name].nil? ||
46
+ expectations[test_name][case_name].nil?
47
+ end
48
+
49
+ raise "no expectation defined for test: '#{test_name}' cases: [#{not_found.join(", ")}]" unless not_found.empty?
50
+
51
+ cases.each do |case_name, predicate|
52
+ actual = block_given? ? yield(predicate) : predicate
53
+ assert { actual == expectations[test_name][case_name] }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def self.included(other)
61
+ other.extend(ClassMethods)
62
+ end
63
+ end