toast 0.4.1 → 0.5.0
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.
- data/app/controller/toast_controller.rb +4 -4
- data/config/routes.rb +1 -0
- data/lib/toast/active_record_extensions.rb +8 -14
- data/lib/toast/association.rb +10 -43
- data/lib/toast/config_dsl.rb +24 -37
- data/lib/toast/engine.rb +17 -0
- data/lib/toast/record.rb +11 -8
- data/lib/toast/resource.rb +25 -15
- data/lib/toast/root_collection.rb +9 -11
- data/lib/toast/single.rb +16 -19
- metadata +4 -4
@@ -4,15 +4,15 @@ class ToastController < ApplicationController
|
|
4
4
|
|
5
5
|
begin
|
6
6
|
|
7
|
-
@resource = Toast::Resource.build( params, request )
|
7
|
+
@resource = Toast::Resource.build( params, request )
|
8
|
+
|
9
|
+
render @resource.apply(request.method, request.body.read)
|
8
10
|
|
9
|
-
render @resource.apply(request.method, request.body.read)
|
10
|
-
|
11
11
|
rescue Toast::ResourceNotFound => e
|
12
12
|
return head(:not_found)
|
13
13
|
|
14
14
|
rescue Toast::PayloadInvalid => e
|
15
|
-
return render :text => e.message, :status => :forbidden
|
15
|
+
return render :text => e.message, :status => :forbidden
|
16
16
|
|
17
17
|
rescue Toast::PayloadFormatError => e
|
18
18
|
return head(:bad_request)
|
data/config/routes.rb
CHANGED
@@ -8,6 +8,7 @@ Rails.application.routes.draw do
|
|
8
8
|
match("#{model.toast_config.namespace}/#{resource_name}(/:id(/:subresource))" => 'toast#catch_all',
|
9
9
|
:constraints => { :id => /\d+/ },
|
10
10
|
:resource => resource_name,
|
11
|
+
:as => resource_name,
|
11
12
|
:defaults => { :format => 'json' })
|
12
13
|
|
13
14
|
match("#{model.toast_config.namespace}/#{resource_name}/:subresource" => 'toast#catch_all',
|
@@ -25,9 +25,12 @@ module Toast
|
|
25
25
|
|
26
26
|
# add instance methods
|
27
27
|
self.class_eval do
|
28
|
-
# Return
|
29
|
-
def
|
30
|
-
"
|
28
|
+
# Return the path segment of the URI of this record
|
29
|
+
def uri_fullpath
|
30
|
+
"/" +
|
31
|
+
(self.class.toast_config.namespace ? self.class.toast_config.namespace+"/" : "") +
|
32
|
+
self.class.to_s.pluralize.underscore + "/" +
|
33
|
+
self.id.to_s
|
31
34
|
end
|
32
35
|
|
33
36
|
# Returns a Hash with all exposed attributes
|
@@ -45,22 +48,13 @@ module Toast
|
|
45
48
|
acc
|
46
49
|
end
|
47
50
|
|
48
|
-
# association URIs
|
49
|
-
exposed_assoc =
|
50
|
-
options[:in_collection] ? self.class.toast_config.in_collection.exposed_associations :
|
51
|
-
self.class.toast_config.exposed_associations
|
52
|
-
|
53
|
-
exposed_assoc.each do |assoc|
|
54
|
-
out[assoc] = self.uri + "/" + assoc
|
55
|
-
end
|
56
|
-
|
57
|
-
out["uri"] = self.uri if options[:with_uri]
|
58
|
-
|
59
51
|
out
|
60
52
|
end
|
61
53
|
end
|
62
54
|
end
|
63
55
|
|
56
|
+
alias acts_as_resource resourceful_model
|
57
|
+
|
64
58
|
# defaults for non resourceful-models
|
65
59
|
def is_resourceful_model?
|
66
60
|
false
|
data/lib/toast/association.rb
CHANGED
@@ -24,12 +24,16 @@ module Toast
|
|
24
24
|
|
25
25
|
if result.is_a? Array
|
26
26
|
{
|
27
|
-
:json => result.map{|r|
|
27
|
+
:json => result.map{|r|
|
28
|
+
r.exposed_attributes(:in_collection => true).
|
29
|
+
merge( uri_fields(r, true) )
|
30
|
+
},
|
28
31
|
:status => :ok
|
29
32
|
}
|
30
33
|
else
|
31
34
|
{
|
32
|
-
:json => result.exposed_attributes(:in_collection => true)
|
35
|
+
:json => result.exposed_attributes(:in_collection => true).
|
36
|
+
merge( uri_fields(result) ),
|
33
37
|
:status => :ok
|
34
38
|
}
|
35
39
|
end
|
@@ -37,48 +41,11 @@ module Toast
|
|
37
41
|
end
|
38
42
|
|
39
43
|
def put payload
|
40
|
-
|
41
|
-
raise MethodNotAllowed if @is_collection
|
42
|
-
|
43
|
-
|
44
|
-
begin
|
45
|
-
payload = ActiveSupport::JSON.decode(payload)
|
46
|
-
rescue
|
47
|
-
raise PayloadFormatError
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
unless payload.is_a? Hash
|
52
|
-
raise PayloadFormatError
|
53
|
-
end
|
54
|
-
|
55
|
-
# update see record
|
56
|
-
if self.media_type != @associate_model.toast_config.media_type
|
57
|
-
raise UnsupportedMediaType
|
58
|
-
end
|
59
|
-
|
60
|
-
# silently ignore all exposed readable, but not writable fields
|
61
|
-
(@associate_model.toast_config.readables - @associate_model.toast_config.writables).each do |rof|
|
62
|
-
payload.delete(rof)
|
63
|
-
end
|
64
|
-
|
65
|
-
record = @record.send(@assoc)
|
66
|
-
|
67
|
-
# set the virtual attributes
|
68
|
-
(payload.keys.to_set - record.attribute_names.to_set).each do |vattr|
|
69
|
-
record.send("#{vattr}=", payload.delete(vattr))
|
70
|
-
end
|
71
|
-
|
72
|
-
# mass-update for the rest
|
73
|
-
record.update_attributes payload
|
74
|
-
{
|
75
|
-
:json => record.exposed_attributes,
|
76
|
-
:status => :ok,
|
77
|
-
:location => record.uri
|
78
|
-
}
|
44
|
+
raise MethodNotAllowed
|
79
45
|
end
|
80
46
|
|
81
47
|
def post payload
|
48
|
+
raise MethodNotAllowed unless @model.toast_config.writables.include? @assoc
|
82
49
|
|
83
50
|
if self.media_type != @associate_model.toast_config.media_type
|
84
51
|
raise UnsupportedMediaType
|
@@ -105,8 +72,8 @@ module Toast
|
|
105
72
|
record = @record.send(@assoc).create! payload
|
106
73
|
|
107
74
|
{
|
108
|
-
:json => record.exposed_attributes,
|
109
|
-
:location => record.
|
75
|
+
:json => record.exposed_attributes.merge( uri_fields(record) ),
|
76
|
+
:location => self.base_uri + record.uri_fullpath,
|
110
77
|
:status => :created
|
111
78
|
}
|
112
79
|
|
data/lib/toast/config_dsl.rb
CHANGED
@@ -7,12 +7,13 @@ module Toast
|
|
7
7
|
|
8
8
|
def initialize model
|
9
9
|
@model = model
|
10
|
-
@readables = [
|
10
|
+
@readables = []
|
11
11
|
@writables = []
|
12
12
|
@collections = []
|
13
13
|
@singles = []
|
14
14
|
@media_type = "application/json"
|
15
|
-
@
|
15
|
+
@deletable = false
|
16
|
+
@postable = false
|
16
17
|
@pass_params_to = []
|
17
18
|
@in_collection = ConfigDSL::InCollection.new model, self
|
18
19
|
end
|
@@ -28,43 +29,40 @@ module Toast
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def readables= arg
|
31
|
-
|
32
|
-
# @readables.push @model.attribute_names - ConfigDSL.sanitize(args.last[:except], "readables")
|
33
|
-
#else
|
34
|
-
@readables.push *ConfigDSL.sanitize(arg,"readables")
|
35
|
-
#end
|
32
|
+
@readables.push *ConfigDSL.sanitize(arg,"readables")
|
36
33
|
end
|
37
34
|
|
38
35
|
# args: Array or :all, :except => Array
|
39
36
|
def readables *arg
|
40
37
|
return(@readables) if arg.empty?
|
41
|
-
self.readables = arg
|
38
|
+
self.readables = arg
|
42
39
|
end
|
43
40
|
|
44
41
|
def writables= arg
|
45
|
-
#if arg.first == :all
|
46
|
-
# @writables.push @model.attribute_names - ConfigDSL.sanitize(args.last[:except], "writables")
|
47
|
-
#else
|
48
|
-
# white list writables (protect the rest from mass-assignment)
|
49
42
|
@model.attr_accessible *arg
|
50
|
-
@writables.push *ConfigDSL.sanitize(arg,"writables")
|
51
|
-
#end
|
43
|
+
@writables.push *ConfigDSL.sanitize(arg,"writables")
|
52
44
|
end
|
53
45
|
|
54
46
|
# args: Array or :all, :except => Array
|
55
47
|
def writables *arg
|
56
48
|
return(@writables) if arg.empty?
|
57
|
-
self.writables = arg
|
49
|
+
self.writables = arg
|
50
|
+
end
|
51
|
+
|
52
|
+
def deletable
|
53
|
+
@deletable = true
|
58
54
|
end
|
59
55
|
|
60
|
-
|
61
|
-
|
62
|
-
@disallow_methods.push *ConfigDSL.sanitize(arg,"disallow methods")
|
56
|
+
def deletable?
|
57
|
+
@deletable
|
63
58
|
end
|
64
59
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
60
|
+
def postable
|
61
|
+
@postable = true
|
62
|
+
end
|
63
|
+
|
64
|
+
def postable?
|
65
|
+
@postable
|
68
66
|
end
|
69
67
|
|
70
68
|
def pass_params_to= arg
|
@@ -73,9 +71,9 @@ module Toast
|
|
73
71
|
|
74
72
|
def pass_params_to *arg
|
75
73
|
return(@pass_params_to) if arg.empty?
|
76
|
-
self.pass_params_to = arg
|
74
|
+
self.pass_params_to = arg
|
77
75
|
end
|
78
|
-
|
76
|
+
|
79
77
|
def collections= collections=[]
|
80
78
|
@collections = ConfigDSL.sanitize(collections, "collections")
|
81
79
|
end
|
@@ -111,15 +109,14 @@ module Toast
|
|
111
109
|
|
112
110
|
def initialize model, base_config
|
113
111
|
@model = model
|
114
|
-
@readables = base_config.readables # must assign a reference
|
115
|
-
@writables = base_config.writables # must assign a reference
|
116
|
-
@disallow_methods = []
|
112
|
+
@readables = base_config.readables # must assign a reference
|
113
|
+
@writables = base_config.writables # must assign a reference
|
117
114
|
@media_type = "application/json"
|
118
115
|
end
|
119
116
|
|
120
117
|
def readables= readables
|
121
118
|
@writables = [] # forget inherited writables
|
122
|
-
@readables = ConfigDSL.sanitize(readables,"readables")
|
119
|
+
@readables = ConfigDSL.sanitize(readables,"readables")
|
123
120
|
end
|
124
121
|
|
125
122
|
def readables *arg
|
@@ -146,16 +143,6 @@ module Toast
|
|
146
143
|
assocs = @model.reflect_on_all_associations.map{|a| a.name.to_s}
|
147
144
|
(@readables + @writables).uniq.select{|f| assocs.include?(f)}
|
148
145
|
end
|
149
|
-
|
150
|
-
def disallow_methods= arg
|
151
|
-
@disallow_methods.push *ConfigDSL.sanitize(arg,"disallow methods")
|
152
|
-
end
|
153
|
-
|
154
|
-
def disallow_methods *arg
|
155
|
-
return(@disallow_methods) if arg.empty?
|
156
|
-
self.disallow_methods = arg
|
157
|
-
end
|
158
|
-
|
159
146
|
end
|
160
147
|
|
161
148
|
|
data/lib/toast/engine.rb
CHANGED
@@ -24,6 +24,23 @@ module Toast
|
|
24
24
|
# raised when DB is not setup yet. (rake db:schema:load)
|
25
25
|
end
|
26
26
|
|
27
|
+
# Monkey patch the request class for Rails 3.0, Rack 1.2
|
28
|
+
# Backport from Rack 1.3
|
29
|
+
if Rack.release == "1.2"
|
30
|
+
class Rack::Request
|
31
|
+
def base_url
|
32
|
+
url = scheme + "://"
|
33
|
+
url << host
|
34
|
+
|
35
|
+
if scheme == "https" && port != 443 ||
|
36
|
+
scheme == "http" && port != 80
|
37
|
+
url << ":#{port}"
|
38
|
+
end
|
39
|
+
|
40
|
+
url
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
27
44
|
end
|
28
45
|
end
|
29
46
|
end
|
data/lib/toast/record.rb
CHANGED
@@ -31,12 +31,12 @@ module Toast
|
|
31
31
|
unless payload.is_a? Hash
|
32
32
|
raise PayloadFormatError
|
33
33
|
end
|
34
|
-
|
35
|
-
#
|
36
|
-
(@model.toast_config.readables - @model.toast_config.writables).each do |rof|
|
34
|
+
|
35
|
+
# ignore all exposed readable, but not writable fields
|
36
|
+
(@model.toast_config.readables - @model.toast_config.writables + ["uri"]).each do |rof|
|
37
37
|
payload.delete(rof)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
# set the virtual attributes
|
41
41
|
(payload.keys.to_set - @record.attribute_names.to_set).each do |vattr|
|
42
42
|
@record.send("#{vattr}=", payload.delete(vattr))
|
@@ -45,9 +45,9 @@ module Toast
|
|
45
45
|
# mass-update for the rest
|
46
46
|
@record.update_attributes payload
|
47
47
|
{
|
48
|
-
:json => @record.exposed_attributes,
|
48
|
+
:json => @record.exposed_attributes.merge( uri_fields(@record) ),
|
49
49
|
:status => :ok,
|
50
|
-
:location => @record.
|
50
|
+
:location => self.base_uri + @record.uri_fullpath
|
51
51
|
}
|
52
52
|
end
|
53
53
|
|
@@ -58,9 +58,9 @@ module Toast
|
|
58
58
|
:template => "resources/#{model.to_s.underscore}",
|
59
59
|
:locals => { model.to_s.underscore.to_sym => @record } # full record, view should filter
|
60
60
|
}
|
61
|
-
when "json"
|
61
|
+
when "json"
|
62
62
|
{
|
63
|
-
:json => @record.exposed_attributes,
|
63
|
+
:json => @record.exposed_attributes.merge( uri_fields(@record) ),
|
64
64
|
:status => :ok
|
65
65
|
}
|
66
66
|
else
|
@@ -69,11 +69,14 @@ module Toast
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def delete
|
72
|
+
raise MethodNotAllowed unless @model.toast_config.deletable?
|
73
|
+
|
72
74
|
@record.destroy
|
73
75
|
{
|
74
76
|
:nothing => true,
|
75
77
|
:status => :ok
|
76
78
|
}
|
77
79
|
end
|
80
|
+
|
78
81
|
end
|
79
82
|
end
|
data/lib/toast/resource.rb
CHANGED
@@ -10,40 +10,37 @@ module Toast
|
|
10
10
|
# Record, RootCollection, Association, Single
|
11
11
|
class Resource
|
12
12
|
|
13
|
-
attr_accessor :media_type
|
13
|
+
attr_accessor :media_type, :base_uri
|
14
14
|
|
15
15
|
def initialize
|
16
16
|
raise 'ToastResource#new: use #build to create an instance'
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.build params, request
|
20
|
-
|
21
20
|
resource_name = params[:resource]
|
22
21
|
id = params[:id]
|
23
22
|
subresource_name = params[:subresource]
|
24
23
|
format = params[:format]
|
25
24
|
|
26
25
|
begin
|
27
|
-
|
26
|
+
|
28
27
|
model = get_class_by_resource_name resource_name
|
29
|
-
|
30
|
-
# base is complete URL until the resource name
|
31
|
-
model.uri_base = request.url.match(/(.*)\/#{resource_name}(?:\..+|\/|\z)/)[1]
|
32
28
|
|
33
29
|
# decide which sub type
|
34
30
|
rsc = if id.nil? and model.toast_config.singles.include?(subresource_name)
|
35
|
-
Toast::Single.new(model, subresource_name, params.clone)
|
31
|
+
Toast::Single.new(model, subresource_name, params.clone)
|
36
32
|
elsif id.nil?
|
37
33
|
Toast::RootCollection.new(model, subresource_name, params.clone)
|
38
34
|
elsif subresource_name.nil?
|
39
35
|
Toast::Record.new(model, id, format)
|
40
36
|
elsif model.toast_config.exposed_associations.include? subresource_name
|
41
|
-
Toast::Association.new(model, id, subresource_name, format)
|
37
|
+
Toast::Association.new(model, id, subresource_name, format)
|
42
38
|
else
|
43
39
|
raise ResourceNotFound
|
44
40
|
end
|
45
|
-
|
41
|
+
|
46
42
|
rsc.media_type = request.media_type
|
43
|
+
rsc.base_uri = request.base_url
|
47
44
|
|
48
45
|
rsc
|
49
46
|
rescue NameError
|
@@ -67,18 +64,31 @@ module Toast
|
|
67
64
|
end
|
68
65
|
|
69
66
|
def apply method, payload
|
70
|
-
|
71
|
-
raise MethodNotAllowed if self.model.toast_config.disallow_methods.include?(method.downcase)
|
72
|
-
|
73
67
|
case method
|
74
68
|
when "PUT","POST"
|
75
69
|
self.send(method.downcase, payload)
|
76
70
|
when "DELETE","GET"
|
77
|
-
|
71
|
+
self.send(method.downcase)
|
78
72
|
else
|
79
73
|
raise MethodNotAllowed
|
80
|
-
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def uri_fields record, in_collection=false
|
79
|
+
out = {}
|
80
|
+
|
81
|
+
exposed_assoc =
|
82
|
+
in_collection ? record.class.toast_config.in_collection.exposed_associations :
|
83
|
+
record.class.toast_config.exposed_associations
|
84
|
+
|
85
|
+
exposed_assoc.each do |assoc|
|
86
|
+
out[assoc] = "#{self.base_uri}#{record.uri_fullpath}/#{assoc}"
|
87
|
+
end
|
88
|
+
|
89
|
+
out["uri"] = self.base_uri + record.uri_fullpath
|
90
|
+
|
91
|
+
out
|
81
92
|
end
|
82
93
|
end
|
83
94
|
end
|
84
|
-
|
@@ -18,9 +18,6 @@ module Toast
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def get
|
21
|
-
if @model.toast_config.in_collection.disallow_methods.include? "get"
|
22
|
-
raise MethodNotAllowed
|
23
|
-
end
|
24
21
|
|
25
22
|
records = if @model.toast_config.pass_params_to.include?(@collection)
|
26
23
|
@model.send(@collection, @params)
|
@@ -36,7 +33,10 @@ module Toast
|
|
36
33
|
}
|
37
34
|
when "json"
|
38
35
|
{
|
39
|
-
:json => records.map{|r|
|
36
|
+
:json => records.map{|r|
|
37
|
+
r.exposed_attributes(:in_collection => true).
|
38
|
+
merge( uri_fields(r, true) )
|
39
|
+
},
|
40
40
|
:status => :ok
|
41
41
|
}
|
42
42
|
else
|
@@ -49,10 +49,8 @@ module Toast
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def post payload
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
|
52
|
+
raise MethodNotAllowed unless @model.toast_config.postable?
|
53
|
+
|
56
54
|
if @collection != "all"
|
57
55
|
raise MethodNotAllowed
|
58
56
|
end
|
@@ -71,7 +69,7 @@ module Toast
|
|
71
69
|
end
|
72
70
|
|
73
71
|
# silently ignore all exposed readable, but not writable fields
|
74
|
-
(@model.toast_config.readables - @model.toast_config.writables).each do |rof|
|
72
|
+
(@model.toast_config.readables - @model.toast_config.writables + ["uri"]).each do |rof|
|
75
73
|
payload.delete(rof)
|
76
74
|
end
|
77
75
|
|
@@ -79,8 +77,8 @@ module Toast
|
|
79
77
|
record = @model.create! payload
|
80
78
|
|
81
79
|
{
|
82
|
-
:json => record.exposed_attributes,
|
83
|
-
:location => record.
|
80
|
+
:json => record.exposed_attributes.merge( uri_fields(record) ),
|
81
|
+
:location => self.base_uri + record.uri_fullpath,
|
84
82
|
:status => :created
|
85
83
|
}
|
86
84
|
|
data/lib/toast/single.rb
CHANGED
@@ -6,47 +6,43 @@ module Toast
|
|
6
6
|
|
7
7
|
# The single resource name must be a class method of the model and
|
8
8
|
# must return nil or an instance.
|
9
|
-
|
9
|
+
|
10
10
|
# GET is the only allowed verb. To make changes the URI with ID has
|
11
11
|
# to be used.
|
12
12
|
class Single < Resource
|
13
|
-
|
13
|
+
|
14
14
|
attr_reader :model
|
15
|
-
|
15
|
+
|
16
16
|
def initialize model, subresource_name, params
|
17
|
-
|
17
|
+
|
18
18
|
unless model.toast_config.singles.include? subresource_name
|
19
19
|
raise ResourceNotFound
|
20
20
|
end
|
21
21
|
|
22
22
|
@model = model
|
23
|
-
@single_finder = subresource_name
|
24
23
|
@params = params
|
25
24
|
@format = params[:format]
|
26
|
-
end
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
raise MethodNotAllowed
|
31
|
-
end
|
32
|
-
|
33
|
-
record = if @model.toast_config.pass_params_to.include?(@single_finder)
|
34
|
-
@model.send(@single_finder, @params)
|
26
|
+
@record = if @model.toast_config.pass_params_to.include?(subresource_name)
|
27
|
+
@model.send(subresource_name, @params)
|
35
28
|
else
|
36
|
-
@model.send(
|
29
|
+
@model.send(subresource_name)
|
37
30
|
end
|
38
31
|
|
39
|
-
raise ResourceNotFound if record.nil?
|
40
|
-
|
32
|
+
raise ResourceNotFound if @record.nil?
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def get
|
41
37
|
case @format
|
42
38
|
when "html"
|
43
39
|
{
|
44
40
|
:template => "resources/#{model.to_s.underscore}",
|
45
|
-
:locals => { model.to_s.pluralize.underscore.to_sym => record }
|
41
|
+
:locals => { model.to_s.pluralize.underscore.to_sym => @record }
|
46
42
|
}
|
47
|
-
when "json"
|
43
|
+
when "json"
|
48
44
|
{
|
49
|
-
:json => record.exposed_attributes,
|
45
|
+
:json => @record.exposed_attributes.merge( uri_fields(@record) ),
|
50
46
|
:status => :ok
|
51
47
|
}
|
52
48
|
else
|
@@ -54,6 +50,7 @@ module Toast
|
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
53
|
+
|
57
54
|
def put
|
58
55
|
raise MethodNotAllowed
|
59
56
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 5
|
8
|
+
- 0
|
9
|
+
version: 0.5.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Robert Annies
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-03-
|
17
|
+
date: 2012-03-20 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|