plucky 0.5.2 → 0.6.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 (46) hide show
  1. data/.bundle/config +4 -0
  2. data/.gitignore +3 -1
  3. data/.travis.yml +2 -2
  4. data/Gemfile +13 -3
  5. data/Guardfile +13 -0
  6. data/README.md +1 -1
  7. data/Rakefile +3 -17
  8. data/examples/query.rb +1 -1
  9. data/lib/plucky.rb +13 -0
  10. data/lib/plucky/criteria_hash.rb +85 -56
  11. data/lib/plucky/normalizers/criteria_hash_key.rb +17 -0
  12. data/lib/plucky/normalizers/criteria_hash_value.rb +83 -0
  13. data/lib/plucky/normalizers/fields_value.rb +26 -0
  14. data/lib/plucky/normalizers/integer.rb +19 -0
  15. data/lib/plucky/normalizers/options_hash_key.rb +23 -0
  16. data/lib/plucky/normalizers/options_hash_value.rb +85 -0
  17. data/lib/plucky/normalizers/sort_value.rb +55 -0
  18. data/lib/plucky/options_hash.rb +56 -85
  19. data/lib/plucky/pagination/decorator.rb +3 -2
  20. data/lib/plucky/pagination/paginator.rb +15 -6
  21. data/lib/plucky/query.rb +93 -51
  22. data/lib/plucky/version.rb +1 -1
  23. data/script/criteria_hash.rb +21 -0
  24. data/{test → spec}/helper.rb +12 -8
  25. data/spec/plucky/criteria_hash_spec.rb +166 -0
  26. data/spec/plucky/normalizers/criteria_hash_key_spec.rb +37 -0
  27. data/spec/plucky/normalizers/criteria_hash_value_spec.rb +193 -0
  28. data/spec/plucky/normalizers/fields_value_spec.rb +45 -0
  29. data/spec/plucky/normalizers/integer_spec.rb +24 -0
  30. data/spec/plucky/normalizers/options_hash_key_spec.rb +23 -0
  31. data/spec/plucky/normalizers/options_hash_value_spec.rb +99 -0
  32. data/spec/plucky/normalizers/sort_value_spec.rb +94 -0
  33. data/spec/plucky/options_hash_spec.rb +64 -0
  34. data/{test/plucky/pagination/test_decorator.rb → spec/plucky/pagination/decorator_spec.rb} +8 -10
  35. data/spec/plucky/pagination/paginator_spec.rb +118 -0
  36. data/spec/plucky/query_spec.rb +839 -0
  37. data/spec/plucky_spec.rb +68 -0
  38. data/{test/test_symbol_operator.rb → spec/symbol_operator_spec.rb} +14 -16
  39. data/spec/symbol_spec.rb +9 -0
  40. metadata +58 -23
  41. data/test/plucky/pagination/test_paginator.rb +0 -120
  42. data/test/plucky/test_criteria_hash.rb +0 -359
  43. data/test/plucky/test_options_hash.rb +0 -302
  44. data/test/plucky/test_query.rb +0 -843
  45. data/test/test_plucky.rb +0 -48
  46. data/test/test_symbol.rb +0 -11
@@ -0,0 +1,26 @@
1
+ module Plucky
2
+ module Normalizers
3
+ class FieldsValue
4
+
5
+ # Public: Given a value returns it normalized for Mongo's fields option
6
+ def call(value)
7
+ return nil if value.respond_to?(:empty?) && value.empty?
8
+
9
+ case value
10
+ when Array
11
+ if value.size == 1 && value.first.is_a?(Hash)
12
+ value.first
13
+ else
14
+ value.flatten
15
+ end
16
+ when Symbol
17
+ [value]
18
+ when String
19
+ value.split(',').map { |v| v.strip }
20
+ else
21
+ value
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ module Plucky
2
+ module Normalizers
3
+ class Integer
4
+
5
+ # Public: Returns value coerced to integer or nil
6
+ #
7
+ # value - The value to normalize to an integer
8
+ #
9
+ # Returns an Integer or nil
10
+ def call(value)
11
+ if value.nil?
12
+ nil
13
+ else
14
+ value.to_i
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ module Plucky
2
+ module Normalizers
3
+ class OptionsHashKey
4
+
5
+ # Internal: Keys with values that they should normalize to
6
+ NormalizedKeys = {
7
+ :order => :sort,
8
+ :select => :fields,
9
+ :offset => :skip,
10
+ :id => :_id,
11
+ }
12
+
13
+ # Public: Normalizes an options hash key
14
+ #
15
+ # key - The key to normalize
16
+ #
17
+ # Returns a Symbol.
18
+ def call(key)
19
+ NormalizedKeys.fetch key.to_sym, key
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,85 @@
1
+ require 'plucky/normalizers/integer'
2
+ require 'plucky/normalizers/fields_value'
3
+ require 'plucky/normalizers/sort_value'
4
+
5
+ module Plucky
6
+ module Normalizers
7
+ class OptionsHashValue
8
+
9
+ # Public: Initialize an OptionsHashValue.
10
+ #
11
+ # args - The hash of arguments (default: {})
12
+ # :key_normalizer - The key normalizer to use, must respond to call
13
+ # :value_normalizers - Hash where key is name of options hash key
14
+ # to normalize and value is what should be used
15
+ # to normalize the value accordingly (must respond
16
+ # to call). Allows adding normalizers for new keys
17
+ # and overriding existing default normalizers.
18
+ #
19
+ #
20
+ # Examples
21
+ #
22
+ # Plucky::Normalizers::OptionsHashValue.new({
23
+ # :key_normalizer => lambda { |key| key}, # key normalizer must responds to call
24
+ # :value_normalizers => {
25
+ # :new_key => lambda { |key| key.to_s.upcase }, # add normalizer for :new_key
26
+ # :fields => lambda { |key| key }, # override normalizer for fields to one that does nothing
27
+ # }
28
+ # })
29
+ #
30
+ # Returns the duplicated String.
31
+ def initialize(args = {})
32
+ @key_normalizer = args.fetch(:key_normalizer) {
33
+ raise ArgumentError, "Missing required key :key_normalizer"
34
+ }
35
+
36
+ @value_normalizers = {
37
+ :fields => default_fields_value_normalizer,
38
+ :sort => default_sort_value_normalizer,
39
+ :limit => default_limit_value_normalizer,
40
+ :skip => default_skip_value_normalizer,
41
+ }
42
+
43
+ if (value_normalizers = args[:value_normalizers])
44
+ @value_normalizers.update(value_normalizers)
45
+ end
46
+ end
47
+
48
+ # Public: Returns value normalized for Mongo
49
+ #
50
+ # key - The name of the key whose value is being normalized
51
+ # value - The value to normalize
52
+ #
53
+ # Returns value normalized for Mongo.
54
+ def call(key, value)
55
+ if (value_normalizer = @value_normalizers[key])
56
+ value_normalizer.call(value)
57
+ else
58
+ value
59
+ end
60
+ end
61
+
62
+ # Private
63
+ def default_fields_value_normalizer
64
+ Normalizers::FieldsValue.new
65
+ end
66
+
67
+ # Private
68
+ def default_sort_value_normalizer
69
+ Normalizers::SortValue.new({
70
+ :key_normalizer => @key_normalizer,
71
+ })
72
+ end
73
+
74
+ # Private
75
+ def default_limit_value_normalizer
76
+ Normalizers::Integer.new
77
+ end
78
+
79
+ # Private
80
+ def default_skip_value_normalizer
81
+ Normalizers::Integer.new
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,55 @@
1
+ module Plucky
2
+ module Normalizers
3
+ class SortValue
4
+
5
+ # Public: Initializes a Plucky::Normalizers::SortValue
6
+ #
7
+ # args - The hash of arguments
8
+ # :key_normalizer - What to use to normalize keys, must
9
+ # respond to call.
10
+ #
11
+ def initialize(args = {})
12
+ @key_normalizer = args.fetch(:key_normalizer) {
13
+ raise ArgumentError, "Missing required key :key_normalizer"
14
+ }
15
+ end
16
+
17
+ # Public: Given a value returns it normalized for Mongo's sort option
18
+ def call(value)
19
+ case value
20
+ when Array
21
+ if value.size == 1 && value[0].is_a?(String)
22
+ normalized_sort_piece(value[0])
23
+ else
24
+ value.compact.map { |v| normalized_sort_piece(v).flatten }
25
+ end
26
+ else
27
+ normalized_sort_piece(value)
28
+ end
29
+ end
30
+
31
+ # Private
32
+ def normalized_sort_piece(value)
33
+ case value
34
+ when SymbolOperator
35
+ [normalized_direction(value.field, value.operator)]
36
+ when String
37
+ value.split(',').map do |piece|
38
+ normalized_direction(*piece.split(' '))
39
+ end
40
+ when Symbol
41
+ [normalized_direction(value)]
42
+ else
43
+ value
44
+ end
45
+ end
46
+
47
+ # Private
48
+ def normalized_direction(field, direction=nil)
49
+ direction ||= 'ASC'
50
+ direction = direction.upcase == 'ASC' ? 1 : -1
51
+ [@key_normalizer.call(field).to_s, direction]
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,127 +1,98 @@
1
1
  # encoding: UTF-8
2
+
3
+ require 'plucky/normalizers/options_hash_key'
4
+ require 'plucky/normalizers/options_hash_value'
5
+
2
6
  module Plucky
3
7
  class OptionsHash
8
+
9
+ # Private: The Hash that stores the query options
4
10
  attr_reader :source
5
11
 
6
- def initialize(hash={})
12
+ # Private: The Hash that stores instance options
13
+ attr_reader :options
14
+
15
+ # Public
16
+ def initialize(hash={}, options={})
7
17
  @source = {}
18
+ @options = options
8
19
  hash.each { |key, value| self[key] = value }
9
20
  end
10
21
 
11
- def initialize_copy(source)
22
+ def initialize_copy(original)
12
23
  super
13
24
  @source = @source.dup
14
- each do |key, value|
25
+ @source.each do |key, value|
15
26
  self[key] = value.clone if value.duplicable?
16
27
  end
17
28
  end
18
29
 
30
+ # Public
31
+ def [](key)
32
+ @source[key]
33
+ end
34
+
35
+ # Public
19
36
  def []=(key, value)
20
37
  key = normalized_key(key)
21
- source[key] = normalized_value(key, value)
38
+ @source[key] = normalized_value(key, value)
22
39
  end
23
40
 
41
+ # Public
42
+ def keys
43
+ @source.keys
44
+ end
45
+
46
+ # Public
24
47
  def ==(other)
25
- source == other.source
48
+ @source == other.source
26
49
  end
27
50
 
51
+ # Public
28
52
  def to_hash
29
- source
53
+ @source
30
54
  end
31
55
 
56
+ # Public
32
57
  def fields?
33
58
  !self[:fields].nil?
34
59
  end
35
60
 
61
+ # Public
36
62
  def merge(other)
37
63
  self.class.new(to_hash.merge(other.to_hash))
38
64
  end
39
65
 
66
+ # Public
40
67
  def merge!(other)
41
68
  other.to_hash.each { |key, value| self[key] = value }
42
69
  self
43
70
  end
44
71
 
45
- private
46
- def method_missing(method, *args, &block)
47
- @source.send(method, *args, &block)
48
- end
49
-
50
- NormalizedKeys = {
51
- :order => :sort,
52
- :select => :fields,
53
- :offset => :skip,
54
- :id => :_id,
55
- }
56
-
57
- def normalized_key(key)
58
- NormalizedKeys.default = key
59
- NormalizedKeys[key.to_sym]
60
- end
61
-
62
- def normalized_value(key, value)
63
- case key
64
- when :fields
65
- normalized_fields(value)
66
- when :sort
67
- normalized_sort(value)
68
- when :limit, :skip
69
- value.nil? ? nil : value.to_i
70
- else
71
- value
72
- end
73
- end
74
-
75
- def normalized_fields(value)
76
- return nil if value.respond_to?(:empty?) && value.empty?
77
- case value
78
- when Array
79
- if value.size == 1 && value.first.is_a?(Hash)
80
- value.first
81
- else
82
- value.flatten
83
- end
84
- when Symbol
85
- [value]
86
- when String
87
- value.split(',').map { |v| v.strip }
88
- else
89
- value
90
- end
91
- end
72
+ # Private
73
+ def normalized_key(key)
74
+ key_normalizer.call(key)
75
+ end
92
76
 
93
- def normalized_sort(value)
94
- case value
95
- when Array
96
- if value.size == 1 && value[0].is_a?(String)
97
- normalized_sort_piece(value[0])
98
- else
99
- value.compact.map { |v| normalized_sort_piece(v).flatten }
100
- end
101
- else
102
- normalized_sort_piece(value)
103
- end
104
- end
77
+ # Private
78
+ def normalized_value(key, value)
79
+ value_normalizer.call(key, value)
80
+ end
105
81
 
106
- def normalized_sort_piece(value)
107
- case value
108
- when SymbolOperator
109
- [normalized_direction(value.field, value.operator)]
110
- when String
111
- value.split(',').map do |piece|
112
- normalized_direction(*piece.split(' '))
113
- end
114
- when Symbol
115
- [normalized_direction(value)]
116
- else
117
- value
118
- end
119
- end
82
+ # Private
83
+ def key_normalizer
84
+ @key_normalizer ||= @options.fetch(:key_normalizer) {
85
+ Normalizers::OptionsHashKey.new
86
+ }
87
+ end
120
88
 
121
- def normalized_direction(field, direction=nil)
122
- direction ||= 'ASC'
123
- direction = direction.upcase == 'ASC' ? 1 : -1
124
- [normalized_key(field).to_s, direction]
125
- end
89
+ # Private
90
+ def value_normalizer
91
+ @value_normalizer ||= @options.fetch(:value_normalizer) {
92
+ Normalizers::OptionsHashValue.new({
93
+ :key_normalizer => key_normalizer,
94
+ })
95
+ }
96
+ end
126
97
  end
127
- end
98
+ end
@@ -8,9 +8,10 @@ module Plucky
8
8
  :total_entries, :total_pages,
9
9
  :current_page, :per_page,
10
10
  :previous_page, :next_page,
11
- :skip, :limit,
11
+ :skip, :limit,
12
12
  :offset, :out_of_bounds?
13
13
 
14
+ # Public
14
15
  def paginator(p=nil)
15
16
  return @paginator if p.nil?
16
17
  @paginator = p
@@ -18,4 +19,4 @@ module Plucky
18
19
  end
19
20
  end
20
21
  end
21
- end
22
+ end
@@ -4,34 +4,43 @@ module Plucky
4
4
  class Paginator
5
5
  attr_reader :total_entries, :current_page, :per_page
6
6
 
7
+ # Public
7
8
  def initialize(total, page, per_page=nil)
8
9
  @total_entries = total.to_i
9
10
  @current_page = [page.to_i, 1].max
10
11
  @per_page = (per_page || 25).to_i
11
12
  end
12
13
 
14
+ # Public
13
15
  def total_pages
14
- (total_entries / per_page.to_f).ceil
16
+ (@total_entries / @per_page.to_f).ceil
15
17
  end
16
18
 
19
+ # Public
17
20
  def out_of_bounds?
18
- current_page > total_pages
21
+ @current_page > total_pages
19
22
  end
20
23
 
24
+ # Public
21
25
  def previous_page
22
- current_page > 1 ? (current_page - 1) : nil
26
+ @current_page > 1 ? (@current_page - 1) : nil
23
27
  end
24
28
 
29
+ # Public
25
30
  def next_page
26
- current_page < total_pages ? (current_page + 1) : nil
31
+ @current_page < total_pages ? (@current_page + 1) : nil
27
32
  end
28
33
 
34
+ # Public
29
35
  def skip
30
- (current_page - 1) * per_page
36
+ (@current_page - 1) * @per_page
31
37
  end
32
38
 
39
+ # Public
33
40
  alias :limit :per_page
41
+
42
+ # Public
34
43
  alias :offset :skip
35
44
  end
36
45
  end
37
- end
46
+ end