set_builder 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +35 -0
  6. data/Rakefile +14 -0
  7. data/assets/javascripts/array.js +100 -0
  8. data/assets/javascripts/set_builder.js +415 -0
  9. data/init.rb +1 -0
  10. data/install.rb +1 -0
  11. data/lib/set_builder.rb +58 -0
  12. data/lib/set_builder/constraint.rb +67 -0
  13. data/lib/set_builder/modifier.rb +134 -0
  14. data/lib/set_builder/modifier/adverb.rb +11 -0
  15. data/lib/set_builder/modifier/base.rb +105 -0
  16. data/lib/set_builder/modifier/verb.rb +24 -0
  17. data/lib/set_builder/modifier_collection.rb +41 -0
  18. data/lib/set_builder/modifiers.rb +3 -0
  19. data/lib/set_builder/modifiers/date_modifier.rb +83 -0
  20. data/lib/set_builder/modifiers/number_modifier.rb +48 -0
  21. data/lib/set_builder/modifiers/string_modifier.rb +81 -0
  22. data/lib/set_builder/query_builders/string.rb +0 -0
  23. data/lib/set_builder/set.rb +81 -0
  24. data/lib/set_builder/trait.rb +74 -0
  25. data/lib/set_builder/traits.rb +42 -0
  26. data/lib/set_builder/value_map.rb +62 -0
  27. data/lib/set_builder/version.rb +3 -0
  28. data/set_builder.gemspec +25 -0
  29. data/spec/commands/example_command.rb +19 -0
  30. data/spec/dom.html +24 -0
  31. data/spec/lib/images/bg.png +0 -0
  32. data/spec/lib/images/hr.png +0 -0
  33. data/spec/lib/images/loading.gif +0 -0
  34. data/spec/lib/images/sprites.bg.png +0 -0
  35. data/spec/lib/images/sprites.png +0 -0
  36. data/spec/lib/images/vr.png +0 -0
  37. data/spec/lib/jspec.css +149 -0
  38. data/spec/lib/jspec.growl.js +115 -0
  39. data/spec/lib/jspec.jquery.js +88 -0
  40. data/spec/lib/jspec.js +1908 -0
  41. data/spec/lib/jspec.nodejs.js +18 -0
  42. data/spec/lib/jspec.shell.js +39 -0
  43. data/spec/lib/jspec.timers.js +154 -0
  44. data/spec/lib/jspec.xhr.js +210 -0
  45. data/spec/node.js +10 -0
  46. data/spec/rhino.js +10 -0
  47. data/spec/server.html +18 -0
  48. data/spec/server.rb +4 -0
  49. data/spec/unit/array.spec.js +82 -0
  50. data/spec/unit/set_builder.spec.js +166 -0
  51. data/spec/unit/spec.helper.js +0 -0
  52. data/test/date_modifier_test.rb +13 -0
  53. data/test/inflector_test.rb +27 -0
  54. data/test/modifier_test.rb +90 -0
  55. data/test/set_test.rb +96 -0
  56. data/test/test_helper.rb +79 -0
  57. data/test/trait_test.rb +49 -0
  58. data/test/traits_test.rb +41 -0
  59. data/test/value_map_test.rb +30 -0
  60. data/uninstall.rb +1 -0
  61. metadata +191 -0
@@ -0,0 +1,3 @@
1
+ require 'set_builder/modifiers/string_modifier'
2
+ require 'set_builder/modifiers/date_modifier'
3
+ require 'set_builder/modifiers/number_modifier'
@@ -0,0 +1,83 @@
1
+ require 'set_builder/modifier/adverb'
2
+
3
+
4
+ module SetBuilder
5
+ module Modifiers
6
+ class DateModifier < Modifier::Adverb
7
+
8
+
9
+
10
+ def self.operators
11
+ {
12
+ :ever => [],
13
+ :before => [:date],
14
+ :after => [:date],
15
+ :on => [:date],
16
+ :during_month => [:month],
17
+ :during_year => [:year],
18
+ :in_the_last => [:number, :period],
19
+ :between => [:date, :date]
20
+ }
21
+ 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
+
50
+ protected
51
+
52
+
53
+
54
+ def get_date
55
+ case operator
56
+ when :in_the_last
57
+ case values[1]
58
+ when "years", "year"
59
+ values[0].to_i.years.ago
60
+ when "months", "month"
61
+ values[0].to_i.months.ago
62
+ when "weeks", "week"
63
+ values[0].to_i.weeks.ago
64
+ when "days", "day"
65
+ values[0].to_i.days.ago
66
+ end
67
+ else
68
+ Date.parse values[0]
69
+ end
70
+ end
71
+
72
+
73
+
74
+ def format_value(date)
75
+ date = [Date.new(1,1,1), date].max # constrain dates to A.D.
76
+ date.strftime('%Y-%m-%d')
77
+ end
78
+
79
+
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,48 @@
1
+ require 'set_builder/modifier/verb'
2
+
3
+
4
+ module SetBuilder
5
+ module Modifiers
6
+ class NumberModifier < Modifier::Verb
7
+
8
+
9
+
10
+ def self.operators
11
+ {
12
+ :is => [:number],
13
+ :is_less_than => [:number],
14
+ :is_greater_than => [:number],
15
+ :is_between => [:number, :number]
16
+ }
17
+ end
18
+
19
+
20
+
21
+ def build_conditions_for(selector)
22
+ case operator
23
+ when :is
24
+ ["#{selector}=?", format_value]
25
+ when :is_less_than
26
+ ["#{selector}<?", format_value]
27
+ when :is_greater_than
28
+ ["#{selector}>?", format_value]
29
+ when :is_between
30
+ ["#{selector}>=? AND #{selector}<=?", values[0], values[1]]
31
+ end
32
+ end
33
+
34
+
35
+
36
+ private
37
+
38
+
39
+
40
+ def format_value
41
+ values[0]
42
+ end
43
+
44
+
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,81 @@
1
+ require 'set_builder/modifier/verb'
2
+
3
+
4
+ module SetBuilder
5
+ module Modifiers
6
+ class StringModifier < Modifier::Verb
7
+
8
+
9
+
10
+ def self.operators
11
+ {
12
+ :contains => [:string],
13
+ :does_not_contain => [:string],
14
+ :begins_with => [:string],
15
+ :does_not_begin_with => [:string],
16
+ :ends_with => [:string],
17
+ :does_not_end_with => [:string],
18
+ :is => [:string],
19
+ :is_not => [:string]
20
+ }
21
+ end
22
+
23
+
24
+
25
+ def self.negate(operator)
26
+ case operator
27
+ when :contains
28
+ "does not contain"
29
+ when :begins_with
30
+ "does not begin with"
31
+ when :ends_with
32
+ "does not end with"
33
+ when :is
34
+ "is not"
35
+ end
36
+ 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
+
62
+ private
63
+
64
+
65
+
66
+ def get_like_value_for_operator
67
+ case operator
68
+ when :contains
69
+ "%#{values[0]}%"
70
+ when :begins_with
71
+ "#{values[0]}%"
72
+ when :ends_with
73
+ "%#{values[0]}"
74
+ end
75
+ end
76
+
77
+
78
+
79
+ end
80
+ end
81
+ end
File without changes
@@ -0,0 +1,81 @@
1
+ module SetBuilder
2
+ class Set
3
+
4
+
5
+
6
+ def initialize(model_or_scope, raw_data)
7
+ @model, @scope = get_model_and_scope(model_or_scope)
8
+ @set = raw_data
9
+ end
10
+
11
+
12
+
13
+ attr_reader :model
14
+
15
+
16
+
17
+ def constraints
18
+ @constraints ||= get_constraints
19
+ end
20
+
21
+
22
+
23
+ #
24
+ # Returns true if all of the constraints in this set are valid
25
+ #
26
+ def valid?
27
+ constraints.all?(&:valid?)
28
+ end
29
+
30
+
31
+
32
+ #
33
+ # Describes this set in natural language
34
+ #
35
+ def to_s
36
+ constraints.to_sentence
37
+ end
38
+
39
+
40
+
41
+ #
42
+ # Returns an instance of ActiveRecord::NamedScope::Scope
43
+ # which can fetch the objects which belong to this set
44
+ #
45
+ def perform
46
+ constraints.inject(@scope) {|scope, constraint| constraint.perform(scope)}
47
+ end
48
+
49
+
50
+
51
+ private
52
+
53
+
54
+
55
+ def get_constraints
56
+ @set.inject([]) do |constraints, line|
57
+ negate, trait_name, args = false, line.first.to_s, line[1..-1]
58
+ trait_name, negate = trait_name[1..-1], true if (trait_name[0..0] == "!")
59
+ trait = model.traits[trait_name]
60
+ raise("\"#{trait_name}\" is not a trait for #{model}") unless trait
61
+ constraints << trait.apply(*args).negate(negate)
62
+ end
63
+ end
64
+
65
+
66
+
67
+ # !todo: this can be overriden or factored out to allow SetBuilder
68
+ # to be used with other ORMs like DataMapper
69
+ def get_model_and_scope(model_or_scope)
70
+ if defined?(ActiveRecord::NamedScope::Scope) && model_or_scope.is_a?(ActiveRecord::NamedScope::Scope)
71
+ [model_or_scope.proxy_scope, model_or_scope]
72
+ else
73
+ # [model_or_scope, model_or_scope.scoped({})]
74
+ [model_or_scope, model_or_scope.scoped]
75
+ end
76
+ end
77
+
78
+
79
+
80
+ end
81
+ end
@@ -0,0 +1,74 @@
1
+ require 'set_builder/constraint'
2
+ require 'set_builder/modifier'
3
+
4
+
5
+ module SetBuilder
6
+ class Trait
7
+
8
+
9
+
10
+ def initialize(name, part_of_speech, *args, &block)
11
+ case name
12
+ when Hash
13
+ @name, @direct_object_type = name.first[0].to_s, name.first[1]
14
+ else
15
+ @name = name.to_s
16
+ end
17
+ @part_of_speech, @block = part_of_speech, block
18
+ @modifiers = (args||[]).collect {|modifier| Modifier[modifier]}
19
+ end
20
+
21
+
22
+
23
+ attr_reader :name, :part_of_speech, :modifiers, :direct_object_type
24
+
25
+
26
+
27
+ def requires_direct_object?
28
+ !@direct_object_type.nil?
29
+ end
30
+ alias :direct_object_required? :requires_direct_object?
31
+
32
+
33
+
34
+ def noun?
35
+ (self.part_of_speech == :noun)
36
+ end
37
+
38
+
39
+
40
+ def to_s(negative=false)
41
+ case part_of_speech
42
+ when :active
43
+ negative ? "who have not #{name}" : "who #{name}"
44
+ when :perfect
45
+ negative ? "who have not #{name}" : "who have #{name}"
46
+ when :passive
47
+ negative ? "who were not #{name}" : "who were #{name}"
48
+ when :reflexive
49
+ negative ? "who are not #{name}" : "who are #{name}"
50
+ when :noun
51
+ "whose #{name}"
52
+ end
53
+ end
54
+
55
+
56
+
57
+ def to_json
58
+ array = []
59
+ array << (requires_direct_object? ? [name, @direct_object_type] : name)
60
+ array << part_of_speech
61
+ array << modifiers.collect{|klass| Modifier.name(klass)} unless modifiers.empty?
62
+ array.to_json
63
+ end
64
+
65
+
66
+
67
+ def apply(*args)
68
+ SetBuilder::Constraint.new(self, *args, &@block)
69
+ end
70
+
71
+
72
+
73
+ end
74
+ end
@@ -0,0 +1,42 @@
1
+ require 'set_builder/trait'
2
+ require 'set_builder/modifier_collection'
3
+
4
+
5
+ module SetBuilder
6
+ class Traits < Array
7
+
8
+
9
+
10
+ def [](index)
11
+ case index
12
+ when Symbol, String
13
+ index = index.to_s
14
+ self.find {|trait| trait.name == index}
15
+ else
16
+ super
17
+ end
18
+ end
19
+
20
+
21
+
22
+ def to_json
23
+ "[#{collect(&:to_json).join(",")}]"
24
+ end
25
+
26
+
27
+
28
+ def modifiers
29
+ # !nb: not sure why inject was failing but it was modifying trait.modifiers!
30
+ @modifiers = ModifierCollection.new
31
+ each do |trait|
32
+ trait.modifiers.each do |modifier|
33
+ @modifiers << modifier unless @modifiers.member?(modifier)
34
+ end
35
+ end
36
+ @modifiers
37
+ end
38
+
39
+
40
+
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ module SetBuilder
2
+ module ValueMap
3
+
4
+
5
+
6
+ @registered_value_maps = {}
7
+
8
+
9
+
10
+ def self.registered?(name)
11
+ name = name.to_sym
12
+ @registered_value_maps.key?(name)
13
+ end
14
+
15
+
16
+
17
+ def self.to_s(name, value)
18
+ name = name.to_sym
19
+ map = @registered_value_maps[name]
20
+ if map
21
+ pair = map.find {|pair| pair[0] == value}
22
+ pair ? pair[1].to_s : "(unknown)"
23
+ else
24
+ value.to_s
25
+ end
26
+ end
27
+
28
+
29
+
30
+ def self.for(name)
31
+ name = name.to_sym
32
+ @registered_value_maps[name] || raise(ArgumentError, "A value map has not been registered for #{value}")
33
+ end
34
+
35
+
36
+
37
+ def self.register_collection(name, collection, name_method = :name, id_method = :id)
38
+ map = collection.map {|i| [i.send(id_method).to_s, i.send(name_method)]}
39
+ register(name, map)
40
+ end
41
+
42
+
43
+
44
+ def self.register(name, map)
45
+ raise "map is expected to be an array of pairs" unless map.is_a?(Array)
46
+ name = name.to_sym
47
+ @registered_value_maps[name] = map
48
+ end
49
+
50
+
51
+
52
+ def self.to_json
53
+ @registered_value_maps.to_json
54
+ end
55
+
56
+
57
+
58
+ end
59
+
60
+
61
+
62
+ end