plucky 0.6.4 → 0.6.5

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.
@@ -77,58 +77,9 @@ module Plucky
77
77
  @source
78
78
  end
79
79
 
80
- # Public and completely disgusting
80
+ # Public
81
81
  def merge(other)
82
- target = @source.dup
83
- other.source.each_key do |key|
84
- value, other_value = target[key], other[key]
85
- target[key] =
86
- if target.key?(key)
87
- value_is_hash = value.is_a?(Hash)
88
- other_is_hash = other_value.is_a?(Hash)
89
-
90
- if value_is_hash && other_is_hash
91
- value.update(other_value) do |key, old_value, new_value|
92
- if old_value.is_a?(Hash) && new_value.is_a?(Hash)
93
- self.class.new(old_value).merge(self.class.new(new_value)).to_hash
94
- else
95
- merge_values_into_array(old_value, new_value)
96
- end
97
- end
98
- elsif value_is_hash && !other_is_hash
99
- if modifier_key = value.keys.detect { |k| Plucky.modifier?(k) }
100
- current_value = value[modifier_key]
101
- value[modifier_key] = current_value.concat(array(other_value)).uniq
102
- else
103
- # kaboom! Array(value).concat(Array(other_value)).uniq
104
- end
105
- elsif other_is_hash && !value_is_hash
106
- if modifier_key = other_value.keys.detect { |k| Plucky.modifier?(k) }
107
- current_value = other_value[modifier_key]
108
- other_value[modifier_key] = current_value.concat(array(value)).uniq
109
- else
110
- # kaboom! Array(value).concat(Array(other_value)).uniq
111
- end
112
- else
113
- merge_values_into_array(value, other_value)
114
- end
115
- else
116
- other_value
117
- end
118
- end
119
- self.class.new(target)
120
- end
121
-
122
- # Private
123
- def merge_values_into_array(value, other_value)
124
- array(value).concat(array(other_value)).uniq
125
- end
126
-
127
- # Private: Array(BSON::ObjectId) returns the byte array or what not instead
128
- # of the object id. This makes sure it is an array of object ids, not the
129
- # guts of the object id.
130
- def array(value)
131
- value.is_a?(BSON::ObjectId) ? [value] : Array(value)
82
+ self.class.new hash_merge(@source, other.source)
132
83
  end
133
84
 
134
85
  # Public
@@ -139,17 +90,6 @@ module Plucky
139
90
  self
140
91
  end
141
92
 
142
- # Private
143
- def object_ids
144
- @options[:object_ids] ||= []
145
- end
146
-
147
- # Private
148
- def object_ids=(value)
149
- raise ArgumentError unless value.is_a?(Array)
150
- @options[:object_ids] = value.flatten
151
- end
152
-
153
93
  # Public: The definition of simple is querying by only _id or _id and _type.
154
94
  # If this is the case, you can use IdentityMap in library to not perform
155
95
  # query and instead just return from map.
@@ -165,6 +105,75 @@ module Plucky
165
105
  object_ids.include?(key.to_sym)
166
106
  end
167
107
 
108
+ # Private
109
+ def object_ids
110
+ @options[:object_ids] ||= []
111
+ end
112
+
113
+ # Private
114
+ def object_ids=(value)
115
+ raise ArgumentError unless value.is_a?(Array)
116
+ @options[:object_ids] = value.flatten
117
+ end
118
+
119
+ private
120
+
121
+ # Private
122
+ def hash_merge(oldhash, newhash)
123
+ merge_compound_or_clauses!(oldhash, newhash)
124
+ oldhash.merge(newhash) do |key, oldval, newval|
125
+ old_is_hash = oldval.instance_of? Hash
126
+ new_is_hash = newval.instance_of? Hash
127
+
128
+ if old_is_hash && new_is_hash
129
+ hash_merge(oldval, newval)
130
+ elsif old_is_hash
131
+ modifier_merge(oldval, newval)
132
+ elsif new_is_hash
133
+ modifier_merge(newval, oldval)
134
+ else
135
+ merge_values_into_array(oldval, newval)
136
+ end
137
+ end
138
+ end
139
+
140
+ def merge_compound_or_clauses!(oldhash, newhash)
141
+ old_or = oldhash[:$or]
142
+ new_or = newhash[:$or]
143
+ if old_or && new_or
144
+ oldhash[:$and] ||= []
145
+ oldhash[:$and] << {:$or => oldhash.delete(:$or)}
146
+ oldhash[:$and] << {:$or => newhash.delete(:$or)}
147
+ elsif new_or && oldhash[:$and]
148
+ if oldhash[:$and].any? {|v| v.key? :$or }
149
+ oldhash[:$and] << {:$or => newhash.delete(:$or)}
150
+ end
151
+ elsif old_or && newhash[:$and]
152
+ if newhash[:$and].any? {|v| v.key? :$or }
153
+ newhash[:$and] << {:$or => oldhash.delete(:$or)}
154
+ end
155
+ end
156
+ end
157
+
158
+ # Private
159
+ def modifier_merge(hash, value)
160
+ if modifier_key = hash.keys.detect { |k| Plucky.modifier?(k) }
161
+ hash[modifier_key].concat( array(value) ).uniq
162
+ end
163
+ end
164
+
165
+ # Private
166
+ def merge_values_into_array(value, other_value)
167
+ array(value).concat(array(other_value)).uniq
168
+ end
169
+
170
+ # Private: Array(BSON::ObjectId) returns the byte array or what not instead
171
+ # of the object id. This makes sure it is an array of object ids, not the
172
+ # guts of the object id.
173
+ def array(value)
174
+ value.is_a?(BSON::ObjectId) ? [value] : Array(value)
175
+ end
176
+
168
177
  # Private
169
178
  def normalized_key(key)
170
179
  key_normalizer.call(key)
@@ -0,0 +1,19 @@
1
+ module Plucky
2
+ module Normalizers
3
+ class HashKey
4
+
5
+ def initialize(keys)
6
+ @keys = keys
7
+ end
8
+
9
+ # Public: Normalizes an options hash key
10
+ #
11
+ # key - The key to normalize
12
+ #
13
+ # Returns a Symbol.
14
+ def call(key)
15
+ @keys.fetch key.to_sym, key
16
+ end
17
+ end
18
+ end
19
+ end
@@ -5,9 +5,9 @@ require 'plucky/normalizers/sort_value'
5
5
  module Plucky
6
6
  module Normalizers
7
7
  class OptionsHashValue
8
-
9
- # Public: Initialize an OptionsHashValue.
10
- #
8
+
9
+ # Public: Initialize an OptionsHashValue.
10
+ #
11
11
  # args - The hash of arguments (default: {})
12
12
  # :key_normalizer - The key normalizer to use, must respond to call
13
13
  # :value_normalizers - Hash where key is name of options hash key
@@ -66,9 +66,7 @@ module Plucky
66
66
 
67
67
  # Private
68
68
  def default_sort_value_normalizer
69
- Normalizers::SortValue.new({
70
- :key_normalizer => @key_normalizer,
71
- })
69
+ Normalizers::SortValue.new(:key_normalizer => Normalizers::HashKey.new({:_id => :id}))
72
70
  end
73
71
 
74
72
  # Private
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'plucky/normalizers/options_hash_key'
3
+ require 'plucky/normalizers/hash_key'
4
4
  require 'plucky/normalizers/options_hash_value'
5
5
 
6
6
  module Plucky
@@ -82,7 +82,12 @@ module Plucky
82
82
  # Private
83
83
  def key_normalizer
84
84
  @key_normalizer ||= @options.fetch(:key_normalizer) {
85
- Normalizers::OptionsHashKey.new
85
+ Normalizers::HashKey.new({
86
+ :order => :sort,
87
+ :select => :fields,
88
+ :offset => :skip,
89
+ :id => :_id,
90
+ })
86
91
  }
87
92
  end
88
93
 
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module Plucky
3
- Version = '0.6.4'
3
+ Version = '0.6.5'
4
4
  end
@@ -0,0 +1,36 @@
1
+ require 'helper'
2
+
3
+ describe Plucky::OptionsHash do
4
+ subject { described_class.new }
5
+
6
+ describe "#[]=" do
7
+ it "changes order to sort" do
8
+ subject[:order] = "foo asc"
9
+ subject[:sort].should == [["foo", 1]]
10
+ subject[:order].should be_nil
11
+ end
12
+
13
+ it "changes select to fields" do
14
+ subject[:select] = [:foo]
15
+ subject[:fields].should == [:foo]
16
+ subject[:select].should be_nil
17
+ end
18
+
19
+ it "changes offset to skip" do
20
+ subject[:offset] = 10
21
+ subject[:skip].should == 10
22
+ subject[:offset].should be_nil
23
+ end
24
+
25
+ it "changes id to _id" do
26
+ subject[:id] = :foo
27
+ subject[:_id].should == :foo
28
+ subject[:id].should be_nil
29
+ end
30
+
31
+ it "does not change the sort field" do
32
+ subject[:order] = :order.asc
33
+ subject[:sort].should == [["order", 1]]
34
+ end
35
+ end
36
+ end
data/spec/helper.rb CHANGED
@@ -17,7 +17,7 @@ Log = Logger.new(File.join(log_dir, 'test.log'))
17
17
 
18
18
  LogBuddy.init :logger => Log
19
19
 
20
- port = ENV.fetch "GH_MONGODB_PORT", 27017
20
+ port = ENV.fetch "BOXEN_MONGODB_PORT", 27017
21
21
  connection = Mongo::MongoClient.new('127.0.0.1', port.to_i, :logger => Log)
22
22
  DB = connection.db('test')
23
23
 
@@ -147,6 +147,40 @@ describe Plucky::CriteriaHash do
147
147
  c1.merge(c2).should_not equal(c1)
148
148
  c1[:foo].should == 'bar'
149
149
  end
150
+
151
+ context "given multiple $or clauses" do
152
+ before do
153
+ @c1 = described_class.new(:$or => [{:a => 1}, {:b => 2}])
154
+ @c2 = described_class.new(:$or => [{:a => 3}, {:b => 4}])
155
+ @c3 = described_class.new(:$or => [{:a => 4}, {:b => 4}])
156
+ end
157
+
158
+ it "merges two $ors into a compound $and" do
159
+ merged = @c1.merge(@c2)
160
+ merged[:$and].should == [
161
+ {:$or => [{:a => 1}, {:b => 2}]},
162
+ {:$or => [{:a => 3}, {:b => 4}]}
163
+ ]
164
+ end
165
+
166
+ it "merges an $and and a $or into a compound $and" do
167
+ merged = @c1.merge(@c2).merge(@c3)
168
+ merged[:$and].should == [
169
+ {:$or => [{:a => 1}, {:b => 2}]},
170
+ {:$or => [{:a => 3}, {:b => 4}]},
171
+ {:$or => [{:a => 4}, {:b => 4}]}
172
+ ]
173
+ end
174
+
175
+ it "merges an $or and an $and into a compound $and" do
176
+ merged = @c3.merge @c1.merge(@c2)
177
+ merged[:$and].should == [
178
+ {:$or => [{:a => 1}, {:b => 2}]},
179
+ {:$or => [{:a => 3}, {:b => 4}]},
180
+ {:$or => [{:a => 4}, {:b => 4}]}
181
+ ]
182
+ end
183
+ end
150
184
  end
151
185
 
152
186
  context "#merge!" do
@@ -0,0 +1,15 @@
1
+ require 'helper'
2
+
3
+ describe Plucky::Normalizers::HashKey do
4
+ subject {
5
+ described_class.new(:bacon => :sizzle)
6
+ }
7
+
8
+ it "changes defined fields" do
9
+ subject.call(:bacon).should eq(:sizzle)
10
+ end
11
+
12
+ it "does not change undefined fields" do
13
+ subject.call(:sausage).should eq(:sausage)
14
+ end
15
+ end
@@ -3,7 +3,7 @@ require 'plucky/normalizers/sort_value'
3
3
 
4
4
  describe Plucky::Normalizers::SortValue do
5
5
  let(:key_normalizer) {
6
- lambda { |key| key == :id ? :_id : key.to_sym }
6
+ Plucky::Normalizers::HashKey.new({:id => :_id})
7
7
  }
8
8
 
9
9
  subject {
@@ -88,6 +88,10 @@ describe Plucky::Normalizers::SortValue do
88
88
  subject.call([:id.asc]).should eq([['_id', 1]])
89
89
  end
90
90
 
91
+ it "doesn't convert keys like :sort to :order via key normalizer" do
92
+ subject.call(:order.asc).should eq([['order', 1]])
93
+ end
94
+
91
95
  it "converts string with $natural correctly" do
92
96
  subject.call('$natural desc').should eq([['$natural', -1]])
93
97
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plucky
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.6.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-03 00:00:00.000000000 Z
12
+ date: 2013-07-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongo
@@ -52,8 +52,8 @@ files:
52
52
  - lib/plucky/normalizers/criteria_hash_key.rb
53
53
  - lib/plucky/normalizers/criteria_hash_value.rb
54
54
  - lib/plucky/normalizers/fields_value.rb
55
+ - lib/plucky/normalizers/hash_key.rb
55
56
  - lib/plucky/normalizers/integer.rb
56
- - lib/plucky/normalizers/options_hash_key.rb
57
57
  - lib/plucky/normalizers/options_hash_value.rb
58
58
  - lib/plucky/normalizers/sort_value.rb
59
59
  - lib/plucky/options_hash.rb
@@ -67,13 +67,14 @@ files:
67
67
  - script/criteria_hash.rb
68
68
  - script/release
69
69
  - script/test
70
+ - spec/functional/options_hash_spec.rb
70
71
  - spec/helper.rb
71
72
  - spec/plucky/criteria_hash_spec.rb
72
73
  - spec/plucky/normalizers/criteria_hash_key_spec.rb
73
74
  - spec/plucky/normalizers/criteria_hash_value_spec.rb
74
75
  - spec/plucky/normalizers/fields_value_spec.rb
76
+ - spec/plucky/normalizers/hash_key_spec.rb
75
77
  - spec/plucky/normalizers/integer_spec.rb
76
- - spec/plucky/normalizers/options_hash_key_spec.rb
77
78
  - spec/plucky/normalizers/options_hash_value_spec.rb
78
79
  - spec/plucky/normalizers/sort_value_spec.rb
79
80
  - spec/plucky/options_hash_spec.rb
@@ -110,13 +111,14 @@ specification_version: 3
110
111
  summary: Thin layer over the ruby driver that allows you to quickly grab hold of your
111
112
  data (pluck it!).
112
113
  test_files:
114
+ - spec/functional/options_hash_spec.rb
113
115
  - spec/helper.rb
114
116
  - spec/plucky/criteria_hash_spec.rb
115
117
  - spec/plucky/normalizers/criteria_hash_key_spec.rb
116
118
  - spec/plucky/normalizers/criteria_hash_value_spec.rb
117
119
  - spec/plucky/normalizers/fields_value_spec.rb
120
+ - spec/plucky/normalizers/hash_key_spec.rb
118
121
  - spec/plucky/normalizers/integer_spec.rb
119
- - spec/plucky/normalizers/options_hash_key_spec.rb
120
122
  - spec/plucky/normalizers/options_hash_value_spec.rb
121
123
  - spec/plucky/normalizers/sort_value_spec.rb
122
124
  - spec/plucky/options_hash_spec.rb
@@ -1,23 +0,0 @@
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
@@ -1,23 +0,0 @@
1
- require 'helper'
2
-
3
- describe Plucky::Normalizers::OptionsHashKey do
4
- subject {
5
- described_class.new
6
- }
7
-
8
- it "changes order to sort" do
9
- subject.call(:order).should eq(:sort)
10
- end
11
-
12
- it "changes select to fields" do
13
- subject.call(:select).should eq(:fields)
14
- end
15
-
16
- it "changes offset to skip" do
17
- subject.call(:offset).should eq(:skip)
18
- end
19
-
20
- it "changes id to _id" do
21
- subject.call(:id).should eq(:_id)
22
- end
23
- end