set_builder 2.0.0.beta2 → 2.0.0.beta3

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 (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"