jonbell-plucky 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 John Nunemaker
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = Plucky
2
+
3
+ Thin layer over the ruby driver that allows you to quickly grab hold of your data (pluck it!).
4
+
5
+ == Install
6
+
7
+ $ gem install plucky
8
+
9
+ == Note on Patches/Pull Requests
10
+
11
+ * Fork the project.
12
+ * Make your feature addition or bug fix.
13
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
14
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
15
+ * Send me a pull request. Bonus points for topic branches.
16
+
17
+ == Copyright
18
+
19
+ Copyright (c) 2010 John Nunemaker. See LICENSE for details.
data/lib/plucky.rb ADDED
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+ require 'set'
3
+ require 'mongo'
4
+ require 'plucky/extensions'
5
+
6
+ module Plucky
7
+ autoload :CriteriaHash, 'plucky/criteria_hash'
8
+ autoload :OptionsHash, 'plucky/options_hash'
9
+ autoload :Query, 'plucky/query'
10
+ autoload :Version, 'plucky/version'
11
+
12
+ module Pagination
13
+ autoload :Decorator, 'plucky/pagination/decorator'
14
+ autoload :Paginator, 'plucky/pagination/paginator'
15
+ end
16
+
17
+ def self.to_object_id(value)
18
+ if value.nil? || (value.respond_to?(:empty?) && value.empty?)
19
+ nil
20
+ elsif value.is_a?(BSON::ObjectId)
21
+ value
22
+ else
23
+ if BSON::ObjectId.legal?(value.to_s)
24
+ BSON::ObjectId.from_string(value.to_s)
25
+ else
26
+ value
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: UTF-8
2
+ module Plucky
3
+ class CriteriaHash
4
+ attr_reader :source, :options
5
+
6
+ def initialize(hash={}, options={})
7
+ @source, @options = {}, options
8
+ hash.each { |key, value| self[key] = value }
9
+ end
10
+
11
+ def initialize_copy(source)
12
+ super
13
+ @options = @options.dup
14
+ @source = @source.dup
15
+ each do |key, value|
16
+ self[key] = value.clone if value.duplicable?
17
+ end
18
+ end
19
+
20
+ def []=(key, value)
21
+ normalized_key = normalized_key(key)
22
+ if key.is_a?(SymbolOperator)
23
+ operator = "$#{key.operator}"
24
+ normalized_value = normalized_value(normalized_key, operator, value)
25
+ source[normalized_key] ||= {}
26
+ source[normalized_key][operator] = normalized_value
27
+ else
28
+ if key == :conditions
29
+ value.each { |k, v| self[k] = v }
30
+ else
31
+ normalized_value = normalized_value(normalized_key, normalized_key, value)
32
+ source[normalized_key] = normalized_value
33
+ end
34
+ end
35
+ end
36
+
37
+ def ==(other)
38
+ source == other.source
39
+ end
40
+
41
+ def to_hash
42
+ source
43
+ end
44
+
45
+ def merge(other)
46
+ target = source.dup
47
+ other.source.each_key do |key|
48
+ value, other_value = target[key], other[key]
49
+ target[key] =
50
+ if target.key?(key)
51
+ value_is_hash = value.is_a?(Hash)
52
+ other_is_hash = other_value.is_a?(Hash)
53
+
54
+ if value_is_hash && other_is_hash
55
+ value.update(other_value) do |key, old_value, new_value|
56
+ Array(old_value).concat(Array(new_value)).uniq
57
+ end
58
+ elsif value_is_hash && !other_is_hash
59
+ if modifier_key = value.keys.detect { |k| k.to_s[0, 1] == '$' }
60
+ value[modifier_key].concat(Array(other_value)).uniq!
61
+ else
62
+ # kaboom! Array(value).concat(Array(other_value)).uniq
63
+ end
64
+ elsif other_is_hash && !value_is_hash
65
+ if modifier_key = other_value.keys.detect { |k| k.to_s[0, 1] == '$' }
66
+ other_value[modifier_key].concat(Array(value)).uniq!
67
+ else
68
+ # kaboom! Array(value).concat(Array(other_value)).uniq
69
+ end
70
+ else
71
+ Array(value).concat(Array(other_value)).uniq
72
+ end
73
+ else
74
+ other_value
75
+ end
76
+ end
77
+ self.class.new(target)
78
+ end
79
+
80
+ def merge!(other)
81
+ merge(other).to_hash.each do |key, value|
82
+ self[key] = value
83
+ end
84
+ end
85
+
86
+ def object_ids
87
+ @options[:object_ids] ||= []
88
+ end
89
+
90
+ def object_ids=(value)
91
+ raise ArgumentError unless value.is_a?(Array)
92
+ @options[:object_ids] = value.flatten
93
+ end
94
+
95
+ # The definition of simple is querying by only _id or _id and _type.
96
+ # If this is the case, you can use IdentityMap in library to not perform
97
+ # query and instead just return from map.
98
+ def simple?
99
+ key_set = keys.to_set
100
+ key_set == [:_id].to_set || key_set == [:_id, :_type].to_set
101
+ end
102
+
103
+ private
104
+ def method_missing(method, *args, &block)
105
+ @source.send(method, *args, &block)
106
+ end
107
+
108
+ def object_id?(key)
109
+ object_ids.include?(key.to_sym)
110
+ end
111
+
112
+ def normalized_key(key)
113
+ key = key.to_sym if key.respond_to?(:to_sym)
114
+ return normalized_key(key.field) if key.respond_to?(:field)
115
+ return :_id if key == :id
116
+ key
117
+ end
118
+
119
+ def normalized_value(parent_key, key, value)
120
+ case value
121
+ when Array, Set
122
+ value.map! { |v| Plucky.to_object_id(v) } if object_id?(parent_key)
123
+ parent_key == key && key != :$or ? {'$in' => value.to_a} : value.to_a
124
+ when Time
125
+ value.utc
126
+ when String
127
+ return Plucky.to_object_id(value) if object_id?(key)
128
+ value
129
+ when Hash
130
+ value.each { |k, v| value[k] = normalized_value(key, k, v) }
131
+ value
132
+ when Regexp
133
+ Regexp.new(value)
134
+ else
135
+ value
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,3 @@
1
+ # encoding: UTF-8
2
+ require 'plucky/extensions/duplicable'
3
+ require 'plucky/extensions/symbol'
@@ -0,0 +1,86 @@
1
+ # Copyright (c) 2005-2010 David Heinemeier Hansson
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ # Most objects are cloneable, but not all. For example you can't dup +nil+:
23
+ #
24
+ # nil.dup # => TypeError: can't dup NilClass
25
+ #
26
+ # Classes may signal their instances are not duplicable removing +dup+/+clone+
27
+ # or raising exceptions from them. So, to dup an arbitrary object you normally
28
+ # use an optimistic approach and are ready to catch an exception, say:
29
+ #
30
+ # arbitrary_object.dup rescue object
31
+ #
32
+ # Rails dups objects in a few critical spots where they are not that arbitrary.
33
+ # That rescue is very expensive (like 40 times slower than a predicate), and it
34
+ # is often triggered.
35
+ #
36
+ # That's why we hardcode the following cases and check duplicable? instead of
37
+ # using that rescue idiom.
38
+ class Object
39
+ # Can you safely .dup this object?
40
+ # False for nil, false, true, symbols, numbers, class and module objects; true otherwise.
41
+ def duplicable?
42
+ true
43
+ end
44
+ end
45
+
46
+ class NilClass #:nodoc:
47
+ def duplicable?
48
+ false
49
+ end
50
+ end
51
+
52
+ class FalseClass #:nodoc:
53
+ def duplicable?
54
+ false
55
+ end
56
+ end
57
+
58
+ class TrueClass #:nodoc:
59
+ def duplicable?
60
+ false
61
+ end
62
+ end
63
+
64
+ class Symbol #:nodoc:
65
+ def duplicable?
66
+ false
67
+ end
68
+ end
69
+
70
+ class Numeric #:nodoc:
71
+ def duplicable?
72
+ false
73
+ end
74
+ end
75
+
76
+ class Class #:nodoc:
77
+ def duplicable?
78
+ false
79
+ end
80
+ end
81
+
82
+ class Module #:nodoc:
83
+ def duplicable?
84
+ false
85
+ end
86
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: UTF-8
2
+ module Plucky
3
+ module Extensions
4
+ module Symbol
5
+ def gt
6
+ SymbolOperator.new(self, 'gt')
7
+ end
8
+
9
+ def lt
10
+ SymbolOperator.new(self, 'lt')
11
+ end
12
+
13
+ def gte
14
+ SymbolOperator.new(self, 'gte')
15
+ end
16
+
17
+ def lte
18
+ SymbolOperator.new(self, 'lte')
19
+ end
20
+
21
+ def ne
22
+ SymbolOperator.new(self, 'ne')
23
+ end
24
+
25
+ def in
26
+ SymbolOperator.new(self, 'in')
27
+ end
28
+
29
+ def nin
30
+ SymbolOperator.new(self, 'nin')
31
+ end
32
+
33
+ def mod
34
+ SymbolOperator.new(self, 'mod')
35
+ end
36
+
37
+ def all
38
+ SymbolOperator.new(self, 'all')
39
+ end
40
+
41
+ def size
42
+ SymbolOperator.new(self, 'size')
43
+ end unless Symbol.instance_methods.include?(:size) # Ruby 1.9 defines symbol size
44
+
45
+ def exists
46
+ SymbolOperator.new(self, 'exists')
47
+ end
48
+
49
+ def asc
50
+ SymbolOperator.new(self, 'asc')
51
+ end
52
+
53
+ def desc
54
+ SymbolOperator.new(self, 'desc')
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ class SymbolOperator
61
+ include Comparable
62
+
63
+ attr_reader :field, :operator
64
+
65
+ def initialize(field, operator, options={})
66
+ @field, @operator = field, operator
67
+ end unless method_defined?(:initialize)
68
+
69
+ def <=>(other)
70
+ if field == other.field
71
+ operator <=> other.operator
72
+ else
73
+ field.to_s <=> other.field.to_s
74
+ end
75
+ end
76
+
77
+ def ==(other)
78
+ field == other.field && operator == other.operator
79
+ end
80
+ end
81
+
82
+ class Symbol
83
+ include Plucky::Extensions::Symbol
84
+ end
@@ -0,0 +1,127 @@
1
+ # encoding: UTF-8
2
+ module Plucky
3
+ class OptionsHash
4
+ attr_reader :source
5
+
6
+ def initialize(hash={})
7
+ @source = {}
8
+ hash.each { |key, value| self[key] = value }
9
+ end
10
+
11
+ def initialize_copy(source)
12
+ super
13
+ @source = @source.dup
14
+ each do |key, value|
15
+ self[key] = value.clone if value.duplicable?
16
+ end
17
+ end
18
+
19
+ def []=(key, value)
20
+ key = normalized_key(key)
21
+ source[key] = normalized_value(key, value)
22
+ end
23
+
24
+ def ==(other)
25
+ source == other.source
26
+ end
27
+
28
+ def to_hash
29
+ source
30
+ end
31
+
32
+ def fields?
33
+ !self[:fields].nil?
34
+ end
35
+
36
+ def merge(other)
37
+ self.class.new(to_hash.merge(other.to_hash))
38
+ end
39
+
40
+ def merge!(other)
41
+ other.to_hash.each { |key, value| self[key] = value }
42
+ self
43
+ end
44
+
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
92
+
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
105
+
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
120
+
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
126
+ end
127
+ end
@@ -0,0 +1,21 @@
1
+ require 'forwardable'
2
+ module Plucky
3
+ module Pagination
4
+ module Decorator
5
+ extend Forwardable
6
+
7
+ def_delegators :@paginator,
8
+ :total_entries, :total_pages,
9
+ :current_page, :per_page,
10
+ :previous_page, :next_page,
11
+ :skip, :limit,
12
+ :offset, :out_of_bounds?
13
+
14
+ def paginator(p=nil)
15
+ return @paginator if p.nil?
16
+ @paginator = p
17
+ self
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: UTF-8
2
+ module Plucky
3
+ module Pagination
4
+ class Paginator
5
+ attr_reader :total_entries, :current_page, :per_page
6
+
7
+ def initialize(total, page, per_page=nil)
8
+ @total_entries = total.to_i
9
+ @current_page = [page.to_i, 1].max
10
+ @per_page = (per_page || 25).to_i
11
+ end
12
+
13
+ def total_pages
14
+ (total_entries / per_page.to_f).ceil
15
+ end
16
+
17
+ def out_of_bounds?
18
+ current_page > total_pages
19
+ end
20
+
21
+ def previous_page
22
+ current_page > 1 ? (current_page - 1) : nil
23
+ end
24
+
25
+ def next_page
26
+ current_page < total_pages ? (current_page + 1) : nil
27
+ end
28
+
29
+ def skip
30
+ (current_page - 1) * per_page
31
+ end
32
+
33
+ alias :limit :per_page
34
+ alias :offset :skip
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,209 @@
1
+ # encoding: UTF-8
2
+ require 'forwardable'
3
+ module Plucky
4
+ class Query
5
+ include Enumerable
6
+ extend Forwardable
7
+
8
+ OptionKeys = [
9
+ :select, :offset, :order, # MM
10
+ :fields, :skip, :limit, :sort, :hint, :snapshot, # Ruby Driver
11
+ :batch_size, :timeout, :transformer # Ruby Driver
12
+ ]
13
+
14
+ attr_reader :criteria, :options, :collection
15
+ def_delegator :criteria, :simple?
16
+ def_delegator :options, :fields?
17
+ def_delegators :to_a, :each, :include?
18
+
19
+ def initialize(collection, opts={})
20
+ @collection, @options, @criteria = collection, OptionsHash.new, CriteriaHash.new
21
+ opts.each { |key, value| self[key] = value }
22
+ end
23
+
24
+ def initialize_copy(source)
25
+ super
26
+ @criteria = @criteria.dup
27
+ @options = @options.dup
28
+ end
29
+
30
+ def object_ids(*keys)
31
+ return criteria.object_ids if keys.empty?
32
+ criteria.object_ids = *keys
33
+ self
34
+ end
35
+
36
+ def per_page(limit=nil)
37
+ return @per_page || 25 if limit.nil?
38
+ @per_page = limit
39
+ self
40
+ end
41
+
42
+ def paginate(opts={})
43
+ page = opts.delete(:page)
44
+ limit = opts.delete(:per_page) || per_page
45
+ query = clone.update(opts)
46
+ total = query.count
47
+ paginator = Pagination::Paginator.new(total, page, limit)
48
+ query[:limit] = paginator.limit
49
+ query[:skip] = paginator.skip
50
+ query.all.tap do |docs|
51
+ docs.extend(Pagination::Decorator)
52
+ docs.paginator(paginator)
53
+ end
54
+ end
55
+
56
+ def find_each(opts={})
57
+ query = clone.update(opts)
58
+ query.collection.find(query.criteria.to_hash, query.options.to_hash)
59
+ end
60
+
61
+ def find_one(opts={})
62
+ query = clone.update(opts)
63
+ query.collection.find_one(query.criteria.to_hash, query.options.to_hash)
64
+ end
65
+
66
+ def find(*ids)
67
+ return nil if ids.empty?
68
+ if ids.size == 1 && !ids[0].is_a?(Array)
69
+ first(:_id => ids[0])
70
+ else
71
+ all(:_id => ids.flatten)
72
+ end
73
+ end
74
+
75
+ def all(opts={})
76
+ find_each(opts).to_a
77
+ end
78
+
79
+ def first(opts={})
80
+ find_one(opts)
81
+ end
82
+
83
+ def last(opts={})
84
+ clone.update(opts).reverse.find_one
85
+ end
86
+
87
+ def remove(opts={})
88
+ query = clone.update(opts)
89
+ query.collection.remove(query.criteria.to_hash)
90
+ end
91
+
92
+ def count(opts={})
93
+ find_each(opts).count
94
+ end
95
+
96
+ def size
97
+ count
98
+ end
99
+
100
+ def distinct(key, opts = {})
101
+ query = clone.update(opts)
102
+ query.collection.distinct(key, query.criteria.to_hash)
103
+ end
104
+
105
+ def update(opts={})
106
+ opts.each { |key, value| self[key] = value }
107
+ self
108
+ end
109
+
110
+ def fields(*args)
111
+ clone.tap { |query| query.options[:fields] = *args }
112
+ end
113
+
114
+ def ignore(*args)
115
+ set_fields(args, 0)
116
+ end
117
+
118
+ def only(*args)
119
+ set_fields(args, 1)
120
+ end
121
+
122
+ def limit(count=nil)
123
+ clone.tap { |query| query.options[:limit] = count }
124
+ end
125
+
126
+ def reverse
127
+ clone.tap do |query|
128
+ query[:sort] = query[:sort].map do |s|
129
+ [s[0], -s[1]]
130
+ end unless query.options[:sort].nil?
131
+ end
132
+ end
133
+
134
+ def skip(count=nil)
135
+ clone.tap { |query| query.options[:skip] = count }
136
+ end
137
+ alias offset skip
138
+
139
+ def sort(*args)
140
+ clone.tap { |query| query.options[:sort] = *args }
141
+ end
142
+ alias order sort
143
+
144
+ def where(hash={})
145
+ clone.tap do |query|
146
+ query.criteria.merge!(CriteriaHash.new(hash))
147
+ end
148
+ end
149
+
150
+ def empty?
151
+ count.zero?
152
+ end
153
+
154
+ def exists?(options={})
155
+ !count(options).zero?
156
+ end
157
+ alias :exist? :exists?
158
+
159
+ def to_a
160
+ all
161
+ end
162
+
163
+ def [](key)
164
+ key = key.to_sym if key.respond_to?(:to_sym)
165
+ if OptionKeys.include?(key)
166
+ @options[key]
167
+ else
168
+ @criteria[key]
169
+ end
170
+ end
171
+
172
+ def []=(key, value)
173
+ key = key.to_sym if key.respond_to?(:to_sym)
174
+ if OptionKeys.include?(key)
175
+ @options[key] = value
176
+ else
177
+ @criteria[key] = value
178
+ end
179
+ end
180
+
181
+ def merge(other)
182
+ merged_criteria = criteria.merge(other.criteria).to_hash
183
+ merged_options = options.merge(other.options).to_hash
184
+ clone.update(merged_criteria).update(merged_options)
185
+ end
186
+
187
+ def to_hash
188
+ criteria.to_hash.merge(options.to_hash)
189
+ end
190
+
191
+ def explain
192
+ collection.find(criteria.to_hash, options.to_hash).explain
193
+ end
194
+
195
+ def inspect
196
+ as_nice_string = to_hash.collect do |key, value|
197
+ " #{key}: #{value.inspect}"
198
+ end.sort.join(",")
199
+ "#<#{self.class}#{as_nice_string}>"
200
+ end
201
+
202
+ private
203
+ def set_fields(field_list, value)
204
+ the_fields = {}
205
+ field_list.each {|field| the_fields[field.to_sym] = value}
206
+ clone.tap { |query| query.options[:fields] = the_fields}
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: UTF-8
2
+ module Plucky
3
+ Version = '0.3.8'
4
+ MongoVersion = '~> 1.3'
5
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jonbell-plucky
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 8
9
+ version: 0.3.8
10
+ platform: ruby
11
+ authors:
12
+ - John Nunemaker
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-06-29 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: jonbell-mongo
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 3
31
+ version: "1.3"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description:
35
+ email:
36
+ - nunemaker@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - lib/plucky/criteria_hash.rb
45
+ - lib/plucky/extensions/duplicable.rb
46
+ - lib/plucky/extensions/symbol.rb
47
+ - lib/plucky/extensions.rb
48
+ - lib/plucky/options_hash.rb
49
+ - lib/plucky/pagination/decorator.rb
50
+ - lib/plucky/pagination/paginator.rb
51
+ - lib/plucky/query.rb
52
+ - lib/plucky/version.rb
53
+ - lib/plucky.rb
54
+ - LICENSE
55
+ - README.rdoc
56
+ has_rdoc: true
57
+ homepage: http://github.com/jonbell/plucky
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options: []
62
+
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Thin layer over the ruby driver that allows you to quickly grab hold of your data (pluck it!).
88
+ test_files: []
89
+