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