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.
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