set_builder 2.0.0.beta2 → 2.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -6
  3. data/Rakefile +2 -2
  4. data/init.rb +1 -1
  5. data/lib/assets/javascripts/set_builder.js +122 -125
  6. data/lib/set_builder/constraint.rb +66 -50
  7. data/lib/set_builder/errors/trait_not_found.rb +3 -0
  8. data/lib/set_builder/modifier/adverb.rb +4 -4
  9. data/lib/set_builder/modifier/base.rb +74 -67
  10. data/lib/set_builder/modifier/verb.rb +1 -16
  11. data/lib/set_builder/modifier.rb +49 -49
  12. data/lib/set_builder/modifier_collection.rb +16 -16
  13. data/lib/set_builder/modifiers/date_preposition.rb +6 -48
  14. data/lib/set_builder/modifiers/number_preposition.rb +4 -25
  15. data/lib/set_builder/modifiers/string_preposition.rb +9 -43
  16. data/lib/set_builder/modifiers.rb +3 -3
  17. data/lib/set_builder/set.rb +48 -8
  18. data/lib/set_builder/trait.rb +75 -49
  19. data/lib/set_builder/traits.rb +13 -4
  20. data/lib/set_builder/value_map.rb +30 -30
  21. data/lib/set_builder/version.rb +1 -1
  22. data/lib/set_builder.rb +8 -7
  23. data/set_builder.gemspec +4 -2
  24. data/spec/commands/example_command.rb +2 -2
  25. data/spec/lib/jspec.css +4 -4
  26. data/spec/lib/jspec.growl.js +11 -11
  27. data/spec/lib/jspec.jquery.js +14 -14
  28. data/spec/lib/jspec.js +210 -210
  29. data/spec/lib/jspec.nodejs.js +2 -2
  30. data/spec/lib/jspec.shell.js +11 -11
  31. data/spec/lib/jspec.timers.js +23 -23
  32. data/spec/rhino.js +1 -1
  33. data/spec/server.rb +1 -1
  34. data/spec/unit/array.spec.js +9 -9
  35. data/spec/unit/set_builder.spec.js +71 -82
  36. data/spec/unit/spec.helper.js +1 -0
  37. data/test/constraint_test.rb +84 -0
  38. data/test/date_preposition_test.rb +17 -7
  39. data/test/modifier_test.rb +26 -1
  40. data/test/set_test.rb +51 -28
  41. data/test/string_preposition_test.rb +10 -9
  42. data/test/test_helper.rb +17 -15
  43. data/test/trait_test.rb +49 -30
  44. data/test/traits_test.rb +35 -30
  45. data/test/value_map_test.rb +1 -1
  46. metadata +37 -15
  47. data/lib/set_builder/query_builders/string.rb +0 -0
  48. data/test/inflector_test.rb +0 -27
@@ -1,11 +1,11 @@
1
- require 'set_builder/modifier/base'
1
+ require "set_builder/modifier/base"
2
2
 
3
3
 
4
4
  module SetBuilder
5
5
  module Modifier
6
6
  class Adverb < Base
7
-
8
-
7
+
8
+
9
9
  end
10
10
  end
11
- end
11
+ end
@@ -1,93 +1,100 @@
1
1
  module SetBuilder
2
2
  module Modifier
3
3
  class Base
4
-
5
-
6
-
7
- def initialize(hash)
8
- @operator, @values = (hash.is_a?(Hash) ? [hash.first[0].to_sym, hash.first[1]] : [nil, nil])
9
- @values ||= []
10
- @values = [@values] unless @values.is_a?(Array)
11
- end
12
-
13
-
14
-
15
4
  attr_reader :operator, :values
16
-
5
+
6
+
7
+
8
+ def initialize(params)
9
+ params.symbolize_keys!
10
+ @operator = params[:operator]
11
+ @operator = @operator.to_sym if @operator
12
+ @values = Array(params[:values])
13
+ end
14
+
15
+
16
+
17
17
  def value
18
18
  values[0]
19
19
  end
20
-
21
-
22
-
20
+
21
+
22
+
23
23
  def valid?
24
- valid_operator?(self.operator) && valid_arguments?(self.values)
24
+ errors.none?
25
25
  end
26
-
27
-
28
-
29
- def valid_operator?(operator)
30
- !operator.nil? && self.class.operators.key?(operator)
26
+
27
+ def errors
28
+ [].tap do |errors|
29
+ errors.concat errors_with_operator
30
+ errors.concat errors_with_values
31
+ end
31
32
  end
32
-
33
-
34
-
35
- def valid_arguments?(values)
36
- argument_types = self.class.operators[operator] || []
37
- return false unless (values.length == argument_types.length)
38
- values.each_with_index do |value, i|
39
- return false unless valid_argument_of_type?(value, argument_types[i])
33
+
34
+ def errors_with_operator
35
+ [].tap do |errors|
36
+ if operator.blank?
37
+ errors.push "operator is blank"
38
+ else
39
+ errors.push "#{operator.inspect} is not recognized. It should be #{self.class.operators.keys.map(&:inspect).to_sentence(two_words_connector: " or ", last_word_connector: ", or ")}" unless self.class.operators.key?(operator)
40
+ end
40
41
  end
41
- true
42
42
  end
43
-
44
-
45
-
46
- def valid_argument_of_type?(argument, type)
47
- validator = "valid_#{type}_argument?"
48
- if respond_to?(validator)
49
- send(validator, argument)
50
- else
51
- true
43
+
44
+ def errors_with_values
45
+ [].tap do |errors|
46
+ types = self.class.operators[operator] || []
47
+ if values.length != types.length
48
+ errors.push "wrong number of arguments; expected #{types.length} (#{types.join(", ")})"
49
+ else
50
+ errors.concat values.each_with_index.flat_map { |value, i| errors_with_value_type(value, types[i]) }
51
+ end
52
52
  end
53
53
  end
54
-
55
-
56
-
57
- def valid_date_argument?(string)
58
- begin
59
- Date.parse(string)
60
- true
61
- rescue
62
- false
54
+
55
+ def errors_with_value_type(value, type)
56
+ validator = "errors_with_#{type}_value"
57
+ if respond_to?(validator)
58
+ Array(public_send(validator, value)).compact
59
+ else
60
+ []
63
61
  end
64
62
  end
65
63
 
66
64
 
67
- def valid_number_argument?(number)
68
- !(number.to_s =~ /\A\d+\Z/).nil?
65
+
66
+ def errors_with_date_value(string)
67
+ return "date is blank" if string.to_s.blank?
68
+ Date.parse(string.to_s)
69
+ nil
70
+ rescue
71
+ "#{string.inspect} is not a valid date"
69
72
  end
70
-
71
-
72
-
73
+
74
+ def errors_with_number_value(string)
75
+ return "number is blank" if string.to_s.blank?
76
+ "#{string.inspect} is not a valid number" unless string.to_s =~ /\A\d+\Z/
77
+ end
78
+
79
+
80
+
73
81
  def to_s(negative=false)
74
82
  words = negative ? [self.class.negate(operator).to_s.gsub(/_/, " ")] : [operator.to_s.gsub(/_/, " ")]
75
83
  arguments = self.class.operators[operator] || []
76
84
  (0...arguments.length).each do |i|
77
- # p "ValueMap.to_s(#{arguments[i]} (#{arguments[i].class}), #{values[i]} (#{values[i].class})): #{ValueMap.to_s(arguments[i], values[i])}"
78
85
  words << ValueMap.to_s(arguments[i], values[i])
79
86
  end
80
87
  words.join(" ")
81
88
  end
82
-
83
-
84
-
89
+
90
+
91
+
85
92
  def self.negate(operator)
86
93
  operator
87
94
  end
88
-
89
-
90
-
95
+
96
+
97
+
91
98
  def self.to_hash
92
99
  hash = {}
93
100
  operators.each do |operator, array|
@@ -95,15 +102,15 @@ module SetBuilder
95
102
  end
96
103
  hash
97
104
  end
98
-
99
-
100
-
105
+
106
+
107
+
101
108
  def self.to_json
102
109
  to_hash.to_json
103
110
  end
104
-
105
-
106
-
111
+
112
+
113
+
107
114
  end
108
115
  end
109
- end
116
+ end
@@ -1,24 +1,9 @@
1
- require 'set_builder/modifier/base'
1
+ require "set_builder/modifier/base"
2
2
 
3
3
 
4
4
  module SetBuilder
5
5
  module Modifier
6
6
  class Verb < Base
7
-
8
-
9
-
10
- protected
11
-
12
-
13
-
14
- def negate(selector, operator)
15
- conditions = build_conditions_for(selector, operator)
16
- conditions[0] = "NOT(#{conditions[0]})"
17
- conditions
18
- end
19
-
20
-
21
-
22
7
  end
23
8
  end
24
9
  end
@@ -1,38 +1,38 @@
1
- require 'set_builder/modifiers'
2
- require 'set_builder/modifier/adverb'
3
- require 'set_builder/modifier/verb'
1
+ require "set_builder/modifiers"
2
+ require "set_builder/modifier/adverb"
3
+ require "set_builder/modifier/verb"
4
4
 
5
5
  module SetBuilder
6
6
  module Modifier
7
-
8
-
9
-
7
+
8
+
9
+
10
10
  @registered_modifiers = {}
11
-
12
-
13
-
11
+
12
+
13
+
14
14
  def self.registered?(klass)
15
15
  @registered_modifiers.values.member?(klass)
16
16
  end
17
-
18
-
19
-
17
+
18
+
19
+
20
20
  def self.name(klass)
21
21
  @registered_modifiers.each do |key, value|
22
22
  return key if (value == klass)
23
23
  end
24
24
  klass.name
25
25
  end
26
-
27
-
28
-
26
+
27
+
28
+
29
29
  def self.for(type)
30
30
  type = get_type(type)
31
31
  @registered_modifiers[type] || raise(ArgumentError, "A modifier has not been registered for #{type}")
32
32
  end
33
-
34
-
35
-
33
+
34
+
35
+
36
36
  def self.[](klassname_or_symbol)
37
37
  is_classname = /^[A-Z]/.match(klassname_or_symbol)
38
38
  if is_classname
@@ -42,10 +42,10 @@ module SetBuilder
42
42
  SetBuilder::Modifier.for(klassname_or_symbol.to_sym)
43
43
  end
44
44
  end
45
-
46
-
47
-
48
- #
45
+
46
+
47
+
48
+ #
49
49
  # Usage
50
50
  # register(type, modifier)
51
51
  # register([type, modifier], [type, modifier])
@@ -60,22 +60,22 @@ module SetBuilder
60
60
  i += 2
61
61
  end
62
62
  end
63
-
64
-
65
-
63
+
64
+
65
+
66
66
  def self.valid_modifier!(klass)
67
67
  raise(ArgumentError, "#{klass} must inherit from either `SetBuilder::Modifier::Verb` or `SetBuilder::Modifier::Adverb`") unless (is_subclass_of?(klass, SetBuilder::Modifier::Adverb) or is_subclass_of?(klass, SetBuilder::Modifier::Verb))
68
68
  raise(ArgumentError, "#{klass} must respond to `operators`") unless klass.respond_to?(:operators)
69
69
  raise(ArgumentError, "#{klass}.operators must not be empty") if klass.operators.empty?
70
70
  klass
71
71
  end
72
-
73
-
74
-
72
+
73
+
74
+
75
75
  private
76
-
77
-
78
-
76
+
77
+
78
+
79
79
  def self.get_type(type)
80
80
  if type.is_a?(Symbol)
81
81
  type
@@ -83,9 +83,9 @@ module SetBuilder
83
83
  type.to_s.downcase.to_sym
84
84
  end
85
85
  end
86
-
87
-
88
-
86
+
87
+
88
+
89
89
  def self.is_subclass_of?(klass, superklass)
90
90
  sc = klass
91
91
  while (sc = sc.superclass)
@@ -93,13 +93,13 @@ module SetBuilder
93
93
  end
94
94
  false
95
95
  end
96
-
97
-
98
-
96
+
97
+
98
+
99
99
  end
100
-
101
-
102
-
100
+
101
+
102
+
103
103
  #
104
104
  # Force predefined modifiers to pass `valid_modifier?`
105
105
  #
@@ -108,9 +108,9 @@ module SetBuilder
108
108
  [:number, Modifiers::NumberPreposition],
109
109
  [:string, Modifiers::StringPreposition]
110
110
  )
111
-
112
-
113
-
111
+
112
+
113
+
114
114
  end
115
115
 
116
116
 
@@ -124,9 +124,9 @@ end
124
124
  #
125
125
 
126
126
  # class Class
127
- #
128
- #
129
- #
127
+ #
128
+ #
129
+ #
130
130
  # def is_subclass_of?(klass)
131
131
  # sc = self
132
132
  # while (sc = sc.superclass)
@@ -134,7 +134,7 @@ end
134
134
  # end
135
135
  # false
136
136
  # end
137
- #
138
- #
139
- #
137
+ #
138
+ #
139
+ #
140
140
  # end
@@ -1,8 +1,8 @@
1
1
  module SetBuilder
2
2
  class ModifierCollection < Array
3
-
4
-
5
-
3
+
4
+
5
+
6
6
  # def [](index)
7
7
  # case index
8
8
  # when Symbol, String
@@ -12,9 +12,9 @@ module SetBuilder
12
12
  # super
13
13
  # end
14
14
  # end
15
-
16
-
17
-
15
+
16
+
17
+
18
18
  def to_hash
19
19
  hash = {}
20
20
  each do |modifier|
@@ -22,20 +22,20 @@ module SetBuilder
22
22
  end
23
23
  hash
24
24
  end
25
-
26
-
27
-
25
+
26
+
27
+
28
28
  def to_json
29
29
  to_hash.to_json
30
30
  end
31
-
32
-
33
-
31
+
32
+
33
+
34
34
  # def modifiers
35
35
  # inject([]) {|modifiers, trait| modifiers.concat(trait.modifiers)}.uniq
36
36
  # end
37
-
38
-
39
-
37
+
38
+
39
+
40
40
  end
41
- end
41
+ end
@@ -1,12 +1,10 @@
1
- require 'set_builder/modifier/adverb'
1
+ require "set_builder/modifier/adverb"
2
2
 
3
3
 
4
4
  module SetBuilder
5
5
  module Modifiers
6
6
  class DatePreposition < Modifier::Adverb
7
-
8
-
9
-
7
+
10
8
  def self.operators
11
9
  {
12
10
  :ever => [],
@@ -19,34 +17,7 @@ module SetBuilder
19
17
  :between => [:date, :date]
20
18
  }
21
19
  end
22
-
23
-
24
-
25
- def build_conditions_for(selector)
26
- case operator
27
- when :ever
28
- "#{selector} IS NOT NULL"
29
- when :before
30
- "#{selector}<'#{format_value(get_date)}'"
31
- when :after
32
- "#{selector}>'#{format_value(get_date)}'"
33
- when :on
34
- "#{selector}='#{format_value(get_date)}'"
35
- when :during_month
36
- "extract(month from #{selector})=#{values[0].to_i}"
37
- when :during_year
38
- year = values[0].to_i
39
- return "TRUE" if year <= 0
40
- "#{selector} BETWEEN '#{year}-01-01' AND '#{year}-12-31'"
41
- when :in_the_last
42
- "#{selector}>='#{format_value(get_date)}'"
43
- when :between
44
- "#{selector} BETWEEN '#{format_value(Date.parse values[0])}' AND '#{format_value(Date.parse values[1])}'"
45
- end
46
- end
47
-
48
-
49
-
20
+
50
21
  def build_arel_for(selector)
51
22
  case operator
52
23
  when :ever
@@ -67,13 +38,9 @@ module SetBuilder
67
38
  selector.in(Date.parse(values[0])..Date.parse(values[1]))
68
39
  end
69
40
  end
70
-
71
-
72
-
41
+
73
42
  protected
74
-
75
-
76
-
43
+
77
44
  def get_date
78
45
  case operator
79
46
  when :in_the_last
@@ -91,16 +58,7 @@ module SetBuilder
91
58
  Date.parse values[0]
92
59
  end
93
60
  end
94
-
95
-
96
-
97
- def format_value(date)
98
- date = [Date.new(1,1,1), date].max # constrain dates to A.D.
99
- date.strftime('%Y-%m-%d')
100
- end
101
-
102
-
103
-
61
+
104
62
  end
105
63
  end
106
64
  end
@@ -1,12 +1,10 @@
1
- require 'set_builder/modifier/verb'
1
+ require "set_builder/modifier/verb"
2
2
 
3
3
 
4
4
  module SetBuilder
5
5
  module Modifiers
6
6
  class NumberPreposition < Modifier::Verb
7
-
8
-
9
-
7
+
10
8
  def self.operators
11
9
  {
12
10
  :is => [:number],
@@ -15,24 +13,7 @@ module SetBuilder
15
13
  :is_between => [:number, :number]
16
14
  }
17
15
  end
18
-
19
-
20
-
21
- def build_conditions_for(selector)
22
- case operator
23
- when :is
24
- ["#{selector}=?", value]
25
- when :is_less_than
26
- ["#{selector}<?", value]
27
- when :is_greater_than
28
- ["#{selector}>?", value]
29
- when :is_between
30
- ["#{selector}>=? AND #{selector}<=?", values[0], values[1]]
31
- end
32
- end
33
-
34
-
35
-
16
+
36
17
  def build_arel_for(selector)
37
18
  case operator
38
19
  when :is
@@ -45,9 +26,7 @@ module SetBuilder
45
26
  selector.gteq(values[0]).and(selector.lteq(values[1]))
46
27
  end
47
28
  end
48
-
49
-
50
-
29
+
51
30
  end
52
31
  end
53
32
  end
@@ -1,12 +1,10 @@
1
- require 'set_builder/modifier/verb'
1
+ require "set_builder/modifier/verb"
2
2
 
3
3
 
4
4
  module SetBuilder
5
5
  module Modifiers
6
6
  class StringPreposition < Modifier::Verb
7
-
8
-
9
-
7
+
10
8
  def self.operators
11
9
  {
12
10
  :contains => [:string],
@@ -19,9 +17,7 @@ module SetBuilder
19
17
  :is_not => [:string]
20
18
  }
21
19
  end
22
-
23
-
24
-
20
+
25
21
  def self.negate(operator)
26
22
  case operator
27
23
  when :contains
@@ -34,51 +30,23 @@ module SetBuilder
34
30
  "is not"
35
31
  end
36
32
  end
37
-
38
-
39
-
40
- def build_conditions_for(selector, operator=nil)
41
- operator ||= self.operator
42
- case operator
43
-
44
- when :does_not_contain
45
- negate(selector, :contains)
46
- when :does_not_begin_with
47
- negate(selector, :begins_with)
48
- when :does_not_end_with
49
- negate(selector, :ends_with)
50
- when :is_not
51
- negate(selector, :is)
52
-
53
- when :is
54
- ["#{selector}=?", values[0]]
55
- else
56
- ["#{selector} LIKE ?", get_like_value_for_operator]
57
- end
58
- end
59
-
60
-
61
-
33
+
62
34
  def build_arel_for(selector, operator=nil)
63
35
  operator ||= self.operator
64
36
  case operator
65
37
  when :is
66
38
  selector.eq(values[0])
67
39
  when :is_not
68
- selector.not_eq(values[0])
40
+ selector.eq(nil).or(selector.not_eq(values[0]))
69
41
  when :contains, :begins_with, :ends_with
70
42
  selector.matches(get_like_value_for_operator)
71
43
  when :does_not_contain, :does_not_begin_with, :does_not_end_with
72
- selector.does_not_match(get_like_value_for_operator)
44
+ selector.eq(nil).or(selector.does_not_match(get_like_value_for_operator))
73
45
  end
74
46
  end
75
-
76
-
77
-
47
+
78
48
  private
79
-
80
-
81
-
49
+
82
50
  def get_like_value_for_operator
83
51
  case operator
84
52
  when :contains, :does_not_contain
@@ -89,9 +57,7 @@ module SetBuilder
89
57
  "%#{values[0]}"
90
58
  end
91
59
  end
92
-
93
-
94
-
60
+
95
61
  end
96
62
  end
97
63
  end
@@ -1,3 +1,3 @@
1
- require 'set_builder/modifiers/string_preposition'
2
- require 'set_builder/modifiers/date_preposition'
3
- require 'set_builder/modifiers/number_preposition'
1
+ require "set_builder/modifiers/string_preposition"
2
+ require "set_builder/modifiers/date_preposition"
3
+ require "set_builder/modifiers/number_preposition"