plucky 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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