acts_as_api 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,7 @@
1
+ === 0.3.4 2011-04-26
2
+
3
+ * Fixed a bug concerning the inheritance of sub templates/additional options
4
+
1
5
  === 0.3.3 2011-04-24
2
6
 
3
7
  * Added support for :if and :unless options
@@ -6,6 +6,7 @@ $:.unshift(File.dirname(__FILE__)) unless
6
6
 
7
7
  require "acts_as_api/array"
8
8
  require "acts_as_api/rails_renderer"
9
+ require "acts_as_api/exceptions"
9
10
 
10
11
  # acts_as_api is a gem that aims to make the construction of JSON and XML
11
12
  # responses in rails 3 easy and fun.
@@ -2,15 +2,17 @@ module ActsAsApi
2
2
  # Represents an api template for a model.
3
3
  # This class should not be initiated by yourself, api templates
4
4
  # are created by defining them in the model by calling: +api_accessible+.
5
- #
5
+ #
6
6
  # The api template is configured in the block passed to +api_accessible+.
7
- #
7
+ #
8
8
  # Please note that +ApiTemplate+ inherits from +Hash+ so you can use all
9
9
  # kind of +Hash+ and +Enumerable+ methods to manipulate the template.
10
10
  class ApiTemplate < Hash
11
11
 
12
12
  # The name of the api template as a Symbol.
13
13
  attr_accessor :api_template
14
+
15
+ attr_reader :options
14
16
 
15
17
  # Returns a new ApiTemplate with the api template name
16
18
  # set to the passed template.
@@ -20,7 +22,16 @@ module ActsAsApi
20
22
  return t
21
23
  end
22
24
 
23
- # Adds an item to the api template
25
+ def initialize
26
+ @options ||= {}
27
+ end
28
+
29
+ def merge!(other_hash, &block)
30
+ super
31
+ self.options.merge!(other_hash.options) if other_hash.respond_to?(:options)
32
+ end
33
+
34
+ # Adds a field to the api template
24
35
  #
25
36
  # The value passed can be one of the following:
26
37
  # * Symbol - the method with the same name will be called on the model when rendering.
@@ -35,42 +46,43 @@ module ActsAsApi
35
46
 
36
47
  self[item_key] = val
37
48
 
38
- @options ||= {}
39
49
  @options[item_key] = options
40
50
  end
41
51
 
42
- # Removes an item from the template
43
- def remove(item)
44
- self.delete(item)
52
+ # Removes a field from the template
53
+ def remove(field)
54
+ self.delete(field)
45
55
  end
46
56
 
47
- # Returns the options of an item in the api template
48
- def options_for(item)
49
- @options[item]
57
+ # Returns the options of a field in the api template
58
+ def options_for(field)
59
+ @options[field]
50
60
  end
51
61
 
52
- # Returns the passed option of an item in the api template
53
- def option_for(item, option)
54
- @options[item][option] if @options[item]
62
+ # Returns the passed option of a field in the api template
63
+ def option_for(field, option)
64
+ @options[field][option] if @options[field]
55
65
  end
56
-
66
+
57
67
  # If a special template name for the passed item is specified
58
68
  # it will be returned, if not the original api template.
59
- def api_template_for(parent, item)
60
- return api_template unless parent.is_a? ActsAsApi::ApiTemplate
61
- parent.option_for(item, :template) || api_template
69
+ def api_template_for(fieldset, field)
70
+ return api_template unless fieldset.is_a? ActsAsApi::ApiTemplate
71
+ fieldset.option_for(field, :template) || api_template
62
72
  end
63
-
73
+
64
74
  # Decides if the passed item should be added to
65
- # the response.
66
- def allowed_to_render?(parent, item, model)
67
- return true unless parent.is_a? ActsAsApi::ApiTemplate
75
+ # the response based on the conditional options passed.
76
+ def allowed_to_render?(fieldset, field, model)
77
+ return true unless fieldset.is_a? ActsAsApi::ApiTemplate
68
78
  allowed = true
69
- allowed = condition_fulfilled?(model, parent.option_for(item, :if)) if parent.option_for(item, :if)
70
- allowed = !(condition_fulfilled?(model, parent.option_for(item, :unless))) if parent.option_for(item, :unless)
79
+ allowed = condition_fulfilled?(model, fieldset.option_for(field, :if)) if fieldset.option_for(field, :if)
80
+ allowed = !(condition_fulfilled?(model, fieldset.option_for(field, :unless))) if fieldset.option_for(field, :unless)
71
81
  return allowed
72
82
  end
73
-
83
+
84
+ # Checks if a condition is fulfilled
85
+ # (result is not nil or false)
74
86
  def condition_fulfilled?(model, condition)
75
87
  case condition
76
88
  when Symbol
@@ -86,48 +98,51 @@ module ActsAsApi
86
98
  def to_response_hash(model)
87
99
  queue = []
88
100
  api_output = {}
89
- queue << { :parent => api_output, :item => self }
101
+
102
+ queue << { :output => api_output, :item => self }
90
103
 
91
104
  until queue.empty? do
92
- leaf = queue.pop
93
-
94
- leaf[:item].each do |k,v|
105
+ leaf = queue.pop
106
+ fieldset = leaf[:item]
107
+
108
+ fieldset.each do |field, value|
95
109
 
96
- next unless allowed_to_render?(leaf[:item], k, model)
110
+ next unless allowed_to_render?(fieldset, field, model)
97
111
 
98
- case v
99
- when Symbol
100
- if model.respond_to?(v)
101
- out = model.send v
102
- end
103
-
104
- when Proc
105
- out = v.call(model)
112
+ case value
113
+ when Symbol
114
+ if model.respond_to?(value)
115
+ out = model.send value
116
+ end
106
117
 
107
- when String
108
- # go up the call chain
109
- out = model
110
- v.split(".").each do |method|
111
- out = out.send(method.to_sym)
112
- end
118
+ when Proc
119
+ out = value.call(model)
113
120
 
114
- when Hash
115
- leaf[:parent][k] ||= {}
116
- queue << { :parent => leaf[:parent][k], :item => v}
117
- next
121
+ when String
122
+ # go up the call chain
123
+ out = model
124
+ value.split(".").each do |method|
125
+ out = out.send(method.to_sym)
118
126
  end
119
127
 
120
- if out.respond_to?(:as_api_response)
121
- sub_template = api_template_for(leaf[:item], k)
122
- out = out.send(:as_api_response, sub_template)
123
- end
128
+ when Hash
129
+ leaf[:output][field] ||= {}
130
+ queue << { :output => leaf[:output][field], :item => value }
131
+ next
132
+ end
124
133
 
125
- leaf[:parent][k] = out
134
+ if out.respond_to?(:as_api_response)
135
+ sub_template = api_template_for(fieldset, field)
136
+ out = out.send(:as_api_response, sub_template)
126
137
  end
127
- end
128
138
 
129
- api_output
139
+ leaf[:output][field] = out
140
+ end
141
+
130
142
  end
131
-
143
+
144
+ api_output
132
145
  end
146
+
133
147
  end
148
+ end
@@ -58,7 +58,7 @@ module ActsAsApi
58
58
  def as_api_response(api_template)
59
59
  api_attributes = self.class.api_accessible_attributes(api_template)
60
60
 
61
- raise "acts_as_api template :#{api_template.to_s} was not found for model #{self.class}" if api_attributes.nil?
61
+ raise ActsAsApi::TemplateNotFoundError.new("acts_as_api template :#{api_template.to_s} was not found for model #{self.class}") if api_attributes.nil?
62
62
 
63
63
  api_attributes.to_response_hash(self)
64
64
  end
@@ -0,0 +1,4 @@
1
+ module ActsAsApi
2
+ class ActsAsApiError < RuntimeError; end
3
+ class TemplateNotFoundError < ActsAsApiError; end
4
+ end
@@ -1,3 +1,3 @@
1
1
  module ActsAsApi
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
@@ -70,5 +70,56 @@ describe ActsAsApi::Base do
70
70
  end
71
71
 
72
72
  end
73
+
74
+ describe "and inherit a field using another template name", :meow => true do
75
+
76
+ before(:each) do
77
+ Task.acts_as_api
78
+ Task.api_accessible :other_template do |t|
79
+ t.add :description
80
+ t.add :time_spent
81
+ end
82
+ User.api_accessible :extending_other_template, :extend => :other_sub_template
83
+ @response = @luke.as_api_response(:extending_other_template)
84
+ end
85
+
86
+ it "returns a hash" do
87
+ @response.should be_kind_of(Hash)
88
+ end
89
+
90
+ it "returns the correct number of fields" do
91
+ @response.should have(2).keys
92
+ end
93
+
94
+ it "returns all specified fields" do
95
+ @response.keys.should include(:first_name)
96
+ end
97
+
98
+ it "returns the correct values for the specified fields" do
99
+ @response.values.should include(@luke.first_name)
100
+ end
101
+
102
+ it "returns all specified fields" do
103
+ @response.keys.should include(:tasks)
104
+ end
105
+
106
+ it "returns the correct values for the specified fields" do
107
+ @response[:tasks].should be_an Array
108
+ @response[:tasks].should have(3).tasks
109
+ end
110
+
111
+ it "contains the associated child models with the determined api template" do
112
+ @response[:tasks].each do |task|
113
+ task.keys.should include(:description, :time_spent)
114
+ task.keys.should have(2).attributes
115
+ end
116
+ end
117
+
118
+ it "contains the correct data of the child models" do
119
+ task_hash = [ @destroy_deathstar, @study_with_yoda, @win_rebellion ].collect{|t| { :description => t.description, :time_spent => t.time_spent } }
120
+ @response[:tasks].should eql task_hash
121
+ end
122
+ end
123
+
73
124
  end
74
125
  end
@@ -13,7 +13,7 @@ describe ActsAsApi::Base do
13
13
  end
14
14
 
15
15
  it "raises an descriptive error" do
16
- lambda{ @luke.as_api_response(:does_not_exist) }.should raise_error(RuntimeError)
16
+ lambda{ @luke.as_api_response(:does_not_exist) }.should raise_error(ActsAsApi::TemplateNotFoundError)
17
17
  end
18
18
 
19
19
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_api
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 3
10
- version: 0.3.3
9
+ - 4
10
+ version: 0.3.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Christian B\xC3\xA4uerlein"
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-24 00:00:00 +02:00
18
+ date: 2011-04-26 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -107,6 +107,7 @@ files:
107
107
  - lib/acts_as_api/array.rb
108
108
  - lib/acts_as_api/base.rb
109
109
  - lib/acts_as_api/config.rb
110
+ - lib/acts_as_api/exceptions.rb
110
111
  - lib/acts_as_api/rails_renderer.rb
111
112
  - lib/acts_as_api/rendering.rb
112
113
  - lib/acts_as_api/version.rb