to_api 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module ToApi
2
- VERSION = "1.1.1"
2
+ VERSION = "1.1.2"
3
3
  end
data/lib/to_api.rb CHANGED
@@ -1,32 +1,80 @@
1
+ module ToApiSelf
2
+ def to_api(*includes)
3
+ self
4
+ end
5
+ end
6
+ [ Fixnum, String, DateTime, Date, Time, NilClass ].each do |klass|
7
+ klass.send(:include, ToApiSelf)
8
+ end
9
+
10
+ module ToApiInstanceMethods
11
+ def build_to_api_include_hash(*includes)
12
+ include_hash = {}
13
+ includes.each do |i|
14
+ if i.kind_of?(Hash)
15
+ i.each do |k,v|
16
+ include_hash[k] = v
17
+ end
18
+ else
19
+ include_hash[i] = []
20
+ end
21
+ end
22
+ include_hash
23
+ end
24
+ end
25
+
26
+ module ToApiFilter
27
+ def add_to_api_filter(include_name, &block)
28
+ @_to_api_filters ||= {}
29
+ @_to_api_filters[include_name] = block
30
+ end
31
+
32
+ def to_api_filters=(filters)
33
+ @_to_api_filters = filters
34
+ end
35
+
36
+ def to_api_filters
37
+ @_to_api_filters ||={}
38
+ @_to_api_filters
39
+ end
40
+ end
41
+
1
42
  if Object.const_defined? :ActiveRecord
43
+
2
44
  class ActiveRecord::Base
45
+ include ToApiFilter
46
+
3
47
  def to_api(*includes) #assumes all attribute types are fine
4
48
  hash = {}
5
- valid_includes = (self.class.reflect_on_all_associations.map(&:name).map(&:to_s) | self.valid_api_includes)
49
+ valid_includes = (self.class.reflect_on_all_associations.map(&:name).map(&:to_s) | self.valid_api_includes | self.attributes.keys)
6
50
 
7
- include_hash = {}
8
- includes.each do |i|
9
- if i.kind_of?(Hash)
10
- i.each do |k,v|
11
- include_hash[k.to_s] = v
12
- end
13
- else
14
- include_hash[i.to_s] = []
51
+ include_hash = build_to_api_ar_include_hash(*includes)
52
+ include_hash.keys.each do |inc|
53
+ if to_api_filters.has_key?(inc)
54
+ child_includes = include_hash.delete(inc) || []
55
+ hash[inc] = to_api_filters[inc].call self, child_includes
15
56
  end
16
57
  end
17
-
58
+
18
59
  include_hash.delete_if{|k,v| !valid_includes.include?(k.to_s)}
19
-
20
60
  to_api_attributes.each do |k, v|
21
- attribute_includes = include_hash[k] || []
22
- v = v.to_api(*attribute_includes)
23
- hash[k] = v
61
+ unless hash[k]
62
+ v.to_api_filters = to_api_filters if v.respond_to? :to_api_filters
63
+
64
+ attribute_includes = include_hash[k] || []
65
+ to_api_v = v.to_api(*[attribute_includes].flatten.compact)
66
+ hash[k] = to_api_v
67
+ end
24
68
  end
25
69
 
26
- (include_hash.keys-attributes.keys).each do |relation|
27
- relation_includes = include_hash[relation] || []
28
- api_obj = self.send(relation)
29
- hash[relation.to_s] = api_obj.respond_to?(:to_api) ? api_obj.to_api(*relation_includes) : api_obj
70
+ (include_hash.keys-to_api_attributes.keys).each do |relation|
71
+ unless hash[relation]
72
+ relation_includes = include_hash[relation] || []
73
+ api_obj = self.send(relation)
74
+ api_obj.to_api_filters = to_api_filters if api_obj.respond_to? :to_api_filters
75
+
76
+ hash[relation.to_s] = api_obj.respond_to?(:to_api) ? api_obj.to_api(*[relation_includes].flatten.compact) : api_obj
77
+ end
30
78
  end
31
79
 
32
80
  hash
@@ -40,58 +88,69 @@ if Object.const_defined? :ActiveRecord
40
88
  def to_api_attributes
41
89
  attributes
42
90
  end
91
+
92
+ private
93
+ def build_to_api_ar_include_hash(*includes)
94
+ include_hash = {}
95
+ includes.each do |i|
96
+ if i.kind_of?(Hash)
97
+ i.each do |k,v|
98
+ include_hash[k.to_s] = v
99
+ end
100
+ else
101
+ include_hash[i.to_s] = []
102
+ end
103
+ end
104
+ include_hash
105
+ end
106
+
43
107
  end
44
108
 
45
109
  #Sadly, Scope isn't enumerable
46
110
  class ActiveRecord::NamedScope::Scope
111
+ include ToApiFilter
47
112
  def to_api(*includes)
48
- map{|e|e.to_api(*includes)}
113
+ map{|e|
114
+ e.to_api_filters = to_api_filters if e.respond_to? :to_api_filters
115
+ e.to_api(*includes)
116
+ }
49
117
  end
50
118
  end
51
119
  end
52
120
 
53
- module Enumerable
54
- def to_api(*includes)
55
- map{|e|e.to_api(*includes)}
56
- end
57
- end
58
-
59
- class Fixnum
121
+ class Array
122
+ include ToApiFilter
60
123
  def to_api(*includes)
61
- self
62
- end
63
- end
124
+ map{|e|
125
+ e.to_api_filters = to_api_filters if e.respond_to? :to_api_filters
64
126
 
65
- class String
66
- def to_api(*includes)
67
- self
127
+ e.to_api(*includes)
128
+ }
68
129
  end
69
130
  end
70
131
 
71
- class DateTime
72
- def to_api(*includes)
73
- self
74
- end
75
- end
76
-
77
- class Date
132
+ class Hash
133
+ include ToApiFilter
134
+ include ToApiInstanceMethods
78
135
  def to_api(*includes)
79
- self
80
- end
81
- end
136
+ values = {}
82
137
 
83
- class Time
84
- def to_api(*includes)
85
- self
86
- end
87
- end
138
+ include_hash = build_to_api_include_hash(*includes)
139
+
140
+ include_hash.keys.each do |inc|
141
+ if to_api_filters.has_key?(inc)
142
+ child_includes = include_hash[inc]
143
+ values[inc] = to_api_filters[inc].call self, child_includes
144
+ end
145
+ end
88
146
 
89
- class Hash
90
- def to_api(*includes)
91
- inject({}) do |memo, (k, v)|
92
- memo[k]=v.to_api(*includes)
93
- memo
147
+ (keys-values.keys).each do |k|
148
+ val = self[k]
149
+ val.to_api_filters = to_api_filters if val.respond_to? :to_api_filters
150
+ child_includes = include_hash[k] || []
151
+ values[k] = val.to_api(*[child_includes].flatten.compact)
94
152
  end
153
+ values
95
154
  end
96
155
  end
97
156
 
@@ -101,8 +160,3 @@ class Symbol
101
160
  end
102
161
  end
103
162
 
104
- class NilClass
105
- def to_api(*includes)
106
- self
107
- end
108
- end
data/spec/to_api_spec.rb CHANGED
@@ -8,6 +8,8 @@ class FakeRecord < ActiveRecord::Base
8
8
  end
9
9
 
10
10
  class OtherFakeRecord < FakeRecord
11
+ def attributes;{"my_field"=>''};end
12
+ def my_field;'yar';end
11
13
  end
12
14
 
13
15
  class FakeChildRecord < FakeRecord
@@ -35,8 +37,8 @@ describe '#to_api' do
35
37
 
36
38
  it "passes on includes" do
37
39
  a = "a"
38
- a.should_receive(:to_api).with(['bar']).and_return(:apiz)
39
- {:one => a}.to_api(['bar']).should == {:one => :apiz}
40
+ a.should_receive(:to_api).with('bar').and_return(:apiz)
41
+ {:one => a}.to_api(:one => ['bar']).should == {:one => :apiz}
40
42
  end
41
43
  end
42
44
 
@@ -108,22 +110,6 @@ describe '#to_api' do
108
110
  end
109
111
  end
110
112
 
111
- describe Enumerable do
112
- class Enumz
113
- attr_accessor :kid
114
- include Enumerable
115
- def each
116
- yield @kid
117
- end
118
- end
119
- it "returns to_api of its kids" do
120
- e = Enumz.new
121
- e.kid = "a"
122
- e.kid.should_receive(:to_api).and_return(:apiz)
123
- [e.kid].to_api.should == [:apiz]
124
- end
125
- end
126
-
127
113
  describe ActiveRecord::NamedScope::Scope do
128
114
  it "returns to_api of its kids" do
129
115
  FakeRecord.should_receive(:reflect_on_all_associations).and_return([mock(:name => "fake_child_records")])
@@ -182,6 +168,10 @@ describe '#to_api' do
182
168
  it "includes the to_api'd attributes" do
183
169
  @base.to_api["age"].should == :apid_age
184
170
  end
171
+
172
+ it "allows the inclusion of attributes" do
173
+ @base.to_api("my_field")["my_field"].should == 'yar'
174
+ end
185
175
  end
186
176
 
187
177
  describe "with includes" do
@@ -258,8 +248,84 @@ describe '#to_api' do
258
248
  @base.to_api("fake_child_records" => "foopy_pantz").should == {"fake_child_records" => [{}]}
259
249
  end
260
250
  end
251
+
252
+ describe "#add_to_api_filter" do
253
+ it "adds a filter" do
254
+ @base = OtherFakeRecord.new
255
+ @base.should_not_receive(:my_field)
256
+ @base.add_to_api_filter("my_field") do |parent, child_includes|
257
+ "YO-HO-HO"
258
+ end
259
+
260
+ @base.to_api("my_field")["my_field"].should == "YO-HO-HO"
261
+ end
262
+
263
+ it "sends filter to child" do
264
+ FakeRecord.stub!(:reflect_on_all_associations => [mock(:name => "kids")])
265
+ FakeChildRecord.stub!(:reflect_on_all_associations => [mock(:name => "foopy_pantz")])
266
+
267
+ @base = FakeRecord.new
268
+ @base.stub!(:attributes => {})
269
+
270
+ @child = FakeChildRecord.new
271
+
272
+ @child.stub!(:foopy_pantz => "pantz of foop")
273
+
274
+ @base.should_receive(:kids).and_return([@child])
275
+
276
+ @base.add_to_api_filter("foopy_pantz") do |parent, child_includes|
277
+ "kachaa"
278
+ end
279
+
280
+ @base.to_api("kids" => "foopy_pantz").should == {"kids" => [{"foopy_pantz" => "kachaa"}]}
281
+ end
282
+ end
283
+ end
284
+ end
285
+
286
+ describe "#add_to_api_filter" do
287
+ before do
288
+ @subhash = {:b => :c, :d => :e}
289
+ @hash = {:a => @subhash}
261
290
  end
262
291
 
292
+ it "puts blocks return value in for filtered key" do
293
+ @hash.add_to_api_filter("count") do |parent, child_includes|
294
+ @hash.count
295
+ end
296
+
297
+ @hash.to_api("count")["count"].should == 1
298
+ end
299
+
300
+ it "nests hashes with filters" do
301
+ @hash.add_to_api_filter("id") do |parent, child_includes|
302
+ parent.object_id
303
+ end
304
+
305
+ api_object = @hash.to_api({"id" => "", :a => "id"})
306
+ api_object["id"].should == @hash.object_id
307
+ api_object[:a]["id"].should == @subhash.object_id
308
+ end
309
+
310
+ it "nests hashes of hashes with filters" do
311
+ @hash.add_to_api_filter("id") do |parent, child_includes|
312
+ parent.object_id
313
+ end
314
+
315
+ api_object = @hash.to_api({"id" => "", :a => {"id" => ""}})
316
+ api_object["id"].should == @hash.object_id
317
+ api_object[:a]["id"].should == @subhash.object_id
318
+ end
319
+
320
+ it "nests hashes with filters with hash params" do
321
+ @hash.add_to_api_filter("id") do |parent, child_includes|
322
+ parent.object_id
323
+ end
324
+
325
+ api_object = @hash.to_api(:a => "id")
326
+ api_object["id"].should be_nil
327
+ api_object[:a]["id"].should == @subhash.object_id
328
+ end
263
329
  end
264
330
  end
265
331
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: to_api
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 1
9
- - 1
10
- version: 1.1.1
9
+ - 2
10
+ version: 1.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Shawn Anderson
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-01-12 00:00:00 -05:00
19
+ date: 2011-01-18 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency