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,4 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require "predicated/gem_check"
4
+ require "predicated/predicate"
@@ -0,0 +1,37 @@
1
+ require "predicated/predicate"
2
+ require "predicated/evaluate"
3
+ require "predicated/string_utils"
4
+
5
+ module Predicated
6
+ class AutogenCall < Call
7
+ def to_s
8
+ method_cameled = StringUtils.uppercamelize(method_sym.to_s)
9
+
10
+ if Predicated.const_defined?(:SimpleTemplatedShorthand) && left == Placeholder
11
+ "#{method_cameled}#{right_to_s}"
12
+ else
13
+ left_str = left_to_s
14
+ right_str = right_to_s
15
+ right_str = "," + right_str unless right_str.empty?
16
+ "#{method_cameled}(#{left_str}#{right_str})"
17
+ end
18
+ end
19
+ end
20
+
21
+ module Shorthand
22
+ def method_missing(uppercase_cameled_method_sym, *args)
23
+ subject = args.shift
24
+ method_sym = StringUtils.underscore(uppercase_cameled_method_sym.to_s).to_sym
25
+ object = args
26
+ AutogenCall.new(subject, method_sym, (object.empty? ? [] : object))
27
+ end
28
+ end
29
+
30
+ module SimpleTemplatedShorthand
31
+ def method_missing(uppercase_cameled_method_sym, *args)
32
+ method_sym = StringUtils.underscore(uppercase_cameled_method_sym.to_s).to_sym
33
+ object = args
34
+ AutogenCall.new(Placeholder, method_sym, (object.empty? ? [] : object))
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,66 @@
1
+ require "predicated/selectable"
2
+
3
+ module Predicated
4
+ class Constraints
5
+ def initialize
6
+ @constraints = []
7
+ end
8
+
9
+ def add(constraint)
10
+ @constraints << constraint
11
+ self
12
+ end
13
+
14
+ def check(whole_predicate)
15
+ result = ConstraintCheckResult.new
16
+
17
+ @constraints.collect do |constraint|
18
+ whole_predicate.select(*constraint.selectors).collect do |predicate, ancestors|
19
+ if ! constraint.check(predicate, ancestors)
20
+ result.violation(constraint, predicate)
21
+ end
22
+ end
23
+ end
24
+
25
+ result
26
+ end
27
+
28
+ def ==(other)
29
+ @constraints == other.instance_variable_get("@constraints".to_sym)
30
+ end
31
+ end
32
+
33
+ class Constraint
34
+ attr_reader :name, :selectors
35
+ def initialize(args)
36
+ @name = args[:name]
37
+ @selectors = args[:selectors] || [:all]
38
+ @check_that = args[:check_that]
39
+ end
40
+
41
+ def check(predicate, ancestors)
42
+ @check_that.call(predicate, ancestors)
43
+ end
44
+
45
+ def ==(other)
46
+ @name == other.name && @selectors == other.selectors
47
+ end
48
+ end
49
+
50
+ class ConstraintCheckResult
51
+ attr_reader :violations
52
+ def initialize
53
+ @violations = {}
54
+ end
55
+
56
+ def pass?
57
+ @violations.empty?
58
+ end
59
+
60
+ def violation(constraint, predicate)
61
+ @violations[constraint] ||= []
62
+ @violations[constraint] << predicate
63
+ self
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,94 @@
1
+ require "predicated/predicate"
2
+
3
+ module Predicated
4
+
5
+
6
+ class Operation < Binary
7
+ attr_reader :method_sym
8
+
9
+ def initialize(left, method_sym, right)
10
+ super(left, right)
11
+ @method_sym = method_sym
12
+ end
13
+
14
+ def evaluate
15
+ right_values = right.nil? ? [nil] : right #1.9 problem where nils and varargs don't play nicely
16
+ left.send(@method_sym, *right_values)
17
+ end
18
+
19
+ def ==(other)
20
+ super && method_sym==other.method_sym
21
+ end
22
+ end
23
+
24
+
25
+ class Equal < Operation; def initialize(left, right); super(left, :==, right); end end
26
+ class LessThan < Operation; def initialize(left, right); super(left, :<, right); end end
27
+ class GreaterThan < Operation; def initialize(left, right); super(left, :>, right); end end
28
+ class LessThanOrEqualTo < Operation; def initialize(left, right); super(left, :<=, right); end end
29
+ class GreaterThanOrEqualTo < Operation; def initialize(left, right); super(left, :>=, right); end end
30
+
31
+ class Call < Operation
32
+ def self.shorthand
33
+ :Call
34
+ end
35
+
36
+ def initialize(left, method_sym, right=[])
37
+ super
38
+ end
39
+
40
+ def to_s
41
+ "Call(#{left_to_s}.#{method_sym.to_s}#{right_to_s})"
42
+ end
43
+
44
+ private
45
+ def left_to_s
46
+ part_to_s(left)
47
+ end
48
+
49
+ def right_to_s
50
+ values = right.is_a?(::Enumerable) ? right : [right]
51
+ values.empty? ? "" :
52
+ "(" + values.collect{|arg|part_to_s(arg)}.join(",") + ")"
53
+ end
54
+ end
55
+ Shorthand.module_eval(%{
56
+ def Call(left_object, method_sym, right_args=[])
57
+ ::Predicated::Call.new(left_object, method_sym, right_args)
58
+ end
59
+ })
60
+
61
+ module Container
62
+ private
63
+ def boolean_or_evaluate(thing)
64
+ if thing.is_a?(FalseClass)
65
+ false
66
+ elsif thing.is_a?(TrueClass)
67
+ true
68
+ else
69
+ thing.evaluate
70
+ end
71
+ end
72
+ end
73
+
74
+ class And
75
+ include Container
76
+ def evaluate
77
+ boolean_or_evaluate(left) && boolean_or_evaluate(right)
78
+ end
79
+ end
80
+
81
+ class Or
82
+ include Container
83
+ def evaluate
84
+ boolean_or_evaluate(left) || boolean_or_evaluate(right)
85
+ end
86
+ end
87
+
88
+ class Not
89
+ include Container
90
+ def evaluate
91
+ ! boolean_or_evaluate(inner)
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,108 @@
1
+ require "predicated/predicate"
2
+ require "predicated/from/ruby_code_string"
3
+
4
+
5
+ #raise %{
6
+ #
7
+ #This will never work in ruby 1.9.
8
+ #
9
+ #see http://blog.zenspider.com/2009/04/parsetree-eol.html
10
+ #
11
+ #} if RUBY_VERSION =~/^1.9/
12
+
13
+ raise %{
14
+
15
+ You appear to be using ruby 1.8.7 and you don't have
16
+ an INLINEDIR environment variable set to a valid directory.
17
+
18
+ ParseTree (used by "from_callable_object") uses RubyInline.
19
+ RubyInline requires that the INLINEDIR environment variable point
20
+ to a directory. The easiest thing to do is to just go
21
+ create a directory somewhere - let's say, ~/inlinedir,
22
+ and point the INLINEDIR at it. In bash this would be:
23
+
24
+ mkdir ~/inlinedir
25
+ export INLINEDIR=~/inlinedir
26
+
27
+ You'll probably want to put this in .bash_profile too.
28
+
29
+ Sorry for the inconvenience. I hope the value you'll
30
+ get out of "from_callable_object" makes it all worth it.
31
+
32
+ } if RUBY_VERSION=="1.8.7" && !ENV["INLINEDIR"]
33
+ #Procs and lambdas are "callable objects"
34
+
35
+ module Predicated
36
+
37
+ require_gem_version("ParseTree", "3.0.5", "parse_tree") if RUBY_VERSION < "1.9"
38
+
39
+ class Predicate
40
+
41
+ #hrm
42
+ def self.from_callable_object(context_or_callable_object=nil, context=nil, &block)
43
+ callable_object = nil
44
+
45
+ if context_or_callable_object.is_a?(Binding) || context_or_callable_object.nil?
46
+ context = context_or_callable_object
47
+ callable_object = block
48
+ else
49
+ callable_object = context_or_callable_object
50
+ end
51
+
52
+ context ||= callable_object.binding
53
+
54
+ from_ruby_code_string(TranslateToRubyString.convert(callable_object), context)
55
+ end
56
+
57
+ module TranslateToRubyString
58
+ #see http://stackoverflow.com/questions/199603/how-do-you-stringize-serialize-ruby-code
59
+ def self.convert(callable_object)
60
+ temp_class = Class.new
61
+ temp_class.class_eval do
62
+ define_method :serializable, &callable_object
63
+ end
64
+ ruby_code_string = Ruby2Ruby.translate(temp_class, :serializable)
65
+ ruby_code_string.sub(/^def serializable\n /, "").sub(/\nend$/, "")
66
+ end
67
+ end
68
+
69
+ #see http://gist.github.com/321038
70
+ # # Monkey-patch to have Ruby2Ruby#translate with r2r >= 1.2.3, from
71
+ # # http://seattlerb.rubyforge.org/svn/ruby2ruby/1.2.2/lib/ruby2ruby.rb
72
+ class ::Ruby2Ruby < ::SexpProcessor
73
+ def self.translate(klass_or_str, method = nil)
74
+ sexp = ParseTree.translate(klass_or_str, method)
75
+ unifier = Unifier.new
76
+ unifier.processors.each do |p|
77
+ p.unsupported.delete :cfunc # HACK
78
+ end
79
+ sexp = unifier.process(sexp)
80
+ self.new.process(sexp)
81
+ end
82
+
83
+ #sconover - 7/2010 - monkey-patch
84
+ #{1=>2}=={1=>2}
85
+ #The right side was having its braces cut off because of
86
+ #special handling of hashes within arglists within the seattlerb code.
87
+ #I tried to fork r2r and add a test, but a lot of other tests
88
+ #broke, and I just dont understand the test in ruby2ruby.
89
+ #So I'm emailing the author...
90
+ def process_hash(exp)
91
+ result = []
92
+ until exp.empty?
93
+ lhs = process(exp.shift)
94
+ rhs = exp.shift
95
+ t = rhs.first
96
+ rhs = process rhs
97
+ rhs = "(#{rhs})" unless [:lit, :str].include? t # TODO: verify better!
98
+
99
+ result << "#{lhs} => #{rhs}"
100
+ end
101
+
102
+ return "{ #{result.join(', ')} }"
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,59 @@
1
+ require "predicated/predicate"
2
+
3
+ module Predicated
4
+
5
+ require_gem_version("json", "1.1.9")
6
+
7
+ class Predicate
8
+ def self.from_json_str(json_str)
9
+ from_json_struct(JSON.parse(json_str))
10
+ end
11
+
12
+ def self.from_json_struct(json_struct)
13
+ JsonStructToPredicate.convert(json_struct)
14
+ end
15
+
16
+ module JsonStructToPredicate
17
+ SIGN_TO_CLASS = {
18
+ "==" => Equal,
19
+ ">" => GreaterThan,
20
+ "<" => LessThan,
21
+ ">=" => GreaterThanOrEqualTo,
22
+ "<=" => LessThanOrEqualTo
23
+ }
24
+
25
+ def self.convert(json_struct)
26
+ if json_struct.is_a?(Array)
27
+ left, sign, right = json_struct
28
+ if operation_class=SIGN_TO_CLASS[sign]
29
+ operation_class.new(left, right)
30
+ else
31
+ raise DontKnowWhatToDoWithThisJson.new(json_struct)
32
+ end
33
+ elsif json_struct.is_a?(Hash)
34
+ if left_and_right=json_struct["and"]
35
+ left, right = left_and_right
36
+ And.new(convert(left), convert(right))
37
+ elsif left_and_right=json_struct["or"]
38
+ left, right = left_and_right
39
+ Or.new(convert(left), convert(right))
40
+ elsif inner=json_struct["not"]
41
+ Not.new(convert(inner))
42
+ else
43
+ raise DontKnowWhatToDoWithThisJson.new(json_struct)
44
+ end
45
+ else
46
+ raise DontKnowWhatToDoWithThisJson.new(json_struct)
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ class DontKnowWhatToDoWithThisJson < StandardError
53
+ def initialize(json_struct)
54
+ super("don't know what to do with #{JSON.generate(json_struct)}")
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,73 @@
1
+ require "predicated/predicate"
2
+ require "predicated/evaluate"
3
+
4
+ module Predicated
5
+
6
+ require_gem_version("ruby_parser", "2.0.4")
7
+ require_gem_version("ruby2ruby", "1.2.4")
8
+
9
+ class Predicate
10
+ def self.from_ruby_code_string(ruby_predicate_string, context=binding())
11
+ sexp = RubyParser.new.process(ruby_predicate_string.strip)
12
+ SexpToPredicate.new(context).convert(sexp)
13
+ end
14
+
15
+ class SexpToPredicate
16
+ SIGN_TO_PREDICATE_CLASS = {
17
+ :== => Equal,
18
+ :> => GreaterThan,
19
+ :< => LessThan,
20
+ :>= => GreaterThanOrEqualTo,
21
+ :<= => LessThanOrEqualTo,
22
+ }
23
+
24
+ def initialize(context)
25
+ @context = context
26
+ end
27
+
28
+ def convert(sexp)
29
+ first_element = sexp.first
30
+ if first_element == :block
31
+ #eval all the top lines and then treat the last one as a predicate
32
+ body_sexps = sexp.sexp_body.to_a
33
+ body_sexps.slice(0..-2).each do |upper_sexp|
34
+ eval_sexp(upper_sexp)
35
+ end
36
+ convert(body_sexps.last)
37
+ elsif first_element == :call
38
+ sym, left_sexp, method_sym, right_sexp = sexp
39
+ left = eval_sexp(left_sexp)
40
+ right = eval_sexp(right_sexp)
41
+
42
+ if operation_class=SIGN_TO_PREDICATE_CLASS[method_sym]
43
+ operation_class.new(left, right)
44
+ else
45
+ Call.new(left, method_sym, right)
46
+ end
47
+ elsif first_element == :and
48
+ sym, left, right = sexp
49
+ And.new(convert(left), convert(right))
50
+ elsif first_element == :or
51
+ sym, left, right = sexp
52
+ Or.new(convert(left), convert(right))
53
+ elsif first_element == :not
54
+ sym, inner = sexp
55
+ Not.new(convert(inner))
56
+ else
57
+ raise DontKnowWhatToDoWithThisSexpError.new(sexp)
58
+ end
59
+ end
60
+
61
+ def eval_sexp(sexp)
62
+ eval(Ruby2Ruby.new.process(sexp), @context)
63
+ end
64
+ end
65
+
66
+
67
+ class DontKnowWhatToDoWithThisSexpError < StandardError
68
+ def initialize(sexp)
69
+ super("don't know what to do with #{sexp.inspect}")
70
+ end
71
+ end
72
+ end
73
+ end