smooth 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -0
- data/Gemfile +1 -2
- data/README.md +150 -5
- data/Rakefile +16 -0
- data/app/assets/javascripts/smooth/index.js +5152 -0
- data/bin/smooth +9 -0
- data/{app/assets/javascripts/smooth → developer-tools}/.keep +0 -0
- data/developer-tools/bower.json +8 -0
- data/developer-tools/config.ru +3 -0
- data/developer-tools/dist/08d606864d3ad3f0b98660d391f5a1c2.gif +0 -0
- data/developer-tools/dist/2d66bcdc27cd89f71068e98a7a929712.gif +0 -0
- data/developer-tools/dist/3e9816417b11485d454f9b3662b06e7b.eot +0 -0
- data/developer-tools/dist/47de617fd1d745ad120ccb9e2924b98c.gif +0 -0
- data/developer-tools/dist/5ae23ad29b67289a1375d2043e289c52.eot +0 -0
- data/developer-tools/dist/60c2a8500e63bf211b7df9608f7613ea.svg +450 -0
- data/developer-tools/dist/645f50ba6c1e56f078fa018855d97eb0.gif +0 -0
- data/developer-tools/dist/71ab514d1cedda303417ad7a06472fea.ttf +0 -0
- data/developer-tools/dist/8cca2f02b0af2da365ff4d1755f29146.ttf +0 -0
- data/developer-tools/dist/939cf252f0eb4efbd2d170c974411c49.gif +0 -0
- data/developer-tools/dist/9af25aaeb6ca6d08d213b04841813eb5.gif +0 -0
- data/developer-tools/dist/b683029bafe0305ac2234038a03e1541.woff +0 -0
- data/developer-tools/dist/c9dec22105ad9330c811599b8b6464f8.woff +0 -0
- data/developer-tools/dist/ca279c55a51ab2641c4712a333633581.gif +0 -0
- data/developer-tools/dist/client.js +5152 -0
- data/developer-tools/dist/f5b27137d3f5e9b1d91b16b37386dd03.gif +0 -0
- data/developer-tools/dist/f99a231ed57ee113b50b1c3e9f9fcdc3.svg +399 -0
- data/developer-tools/dist/index.html +18 -0
- data/developer-tools/dist/inspector.js +38432 -0
- data/developer-tools/dist/jquery.min.js +9190 -0
- data/developer-tools/package.json +39 -0
- data/developer-tools/server.js +14 -0
- data/developer-tools/src/client.coffee +21 -0
- data/developer-tools/src/client/collection.coffee +14 -0
- data/developer-tools/src/client/model.coffee +11 -0
- data/developer-tools/src/client/resource.coffee +132 -0
- data/{app/controllers/.keep → developer-tools/src/client/runner.coffee} +0 -0
- data/developer-tools/src/dependencies.coffee +7 -0
- data/developer-tools/src/inspector.cjsx +49 -0
- data/developer-tools/src/inspector/models/interface_collection.coffee +31 -0
- data/developer-tools/src/inspector/pages/index.cjsx +31 -0
- data/developer-tools/src/inspector/pages/resources.cjsx +5 -0
- data/developer-tools/src/inspector/views/grid_sort.cjsx +23 -0
- data/developer-tools/src/inspector/views/icon_heading.cjsx +15 -0
- data/developer-tools/src/inspector/views/resource_card.cjsx +34 -0
- data/developer-tools/src/inspector/views/sidebar.cjsx +12 -0
- data/developer-tools/src/inspector/views/toolbar.cjsx +17 -0
- data/developer-tools/src/styles/index.scss +136 -0
- data/developer-tools/src/styles/views.scss +13 -0
- data/developer-tools/src/util.coffee +48 -0
- data/developer-tools/webpack.config.js +56 -0
- data/developer-tools/webpack.hot.config.js +65 -0
- data/lib/smooth.rb +209 -28
- data/lib/smooth/active_record/adapter.rb +24 -0
- data/lib/smooth/api.rb +272 -18
- data/lib/smooth/api/policy.rb +2 -2
- data/lib/smooth/api/tracking.rb +4 -4
- data/lib/smooth/application.rb +66 -0
- data/lib/smooth/cache.rb +1 -1
- data/lib/smooth/command.rb +267 -18
- data/lib/smooth/command/async_worker.rb +27 -0
- data/lib/smooth/command/instrumented.rb +6 -4
- data/lib/smooth/command/run_proxy.rb +21 -0
- data/lib/smooth/configuration.rb +63 -8
- data/lib/smooth/documentation.rb +3 -6
- data/lib/smooth/dsl.rb +1 -36
- data/lib/smooth/dsl_adapter.rb +34 -0
- data/lib/smooth/event.rb +8 -4
- data/lib/smooth/event/proxy.rb +9 -0
- data/lib/smooth/event/relay.rb +38 -0
- data/lib/smooth/example.rb +1 -1
- data/lib/smooth/ext/core.rb +16 -0
- data/lib/smooth/model_adapter.rb +31 -0
- data/lib/smooth/query.rb +143 -13
- data/lib/smooth/resource.rb +227 -52
- data/lib/smooth/resource/router.rb +217 -0
- data/lib/smooth/resource/templating.rb +62 -0
- data/lib/smooth/resource/tracking.rb +1 -1
- data/lib/smooth/response.rb +73 -0
- data/lib/smooth/serializer.rb +102 -11
- data/lib/smooth/user_adapter.rb +83 -0
- data/lib/smooth/util.rb +17 -0
- data/lib/smooth/version.rb +1 -1
- data/smooth.gemspec +6 -2
- data/spec/acceptance/books_routes_spec.rb +50 -0
- data/spec/acceptance/embedded_relationships_spec.rb +26 -0
- data/spec/dummy/app/apis/application_api.rb +8 -3
- data/spec/dummy/app/commands/create_book.rb +5 -0
- data/spec/dummy/app/models/book.rb +1 -0
- data/spec/dummy/app/models/library.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/app/queries/book_query.rb +13 -0
- data/spec/dummy/app/resources/{books.rb → books_definition.rb} +37 -12
- data/spec/dummy/db/migrate/20140824215902_create_users.rb +10 -0
- data/spec/dummy/db/migrate/20140826193259_create_libraries.rb +10 -0
- data/spec/dummy/db/schema.rb +8 -1
- data/spec/lib/smooth/api/async_spec.rb +21 -0
- data/spec/lib/smooth/api_spec.rb +8 -0
- data/spec/lib/smooth/command_spec.rb +87 -6
- data/spec/lib/smooth/configuration_spec.rb +4 -0
- data/spec/lib/smooth/event/relay_spec.rb +33 -0
- data/spec/lib/smooth/event_spec.rb +5 -8
- data/spec/lib/smooth/query_spec.rb +42 -0
- data/spec/lib/smooth/resource/router_spec.rb +14 -0
- data/spec/lib/smooth/resource_spec.rb +33 -1
- data/spec/lib/smooth/serializer_spec.rb +20 -0
- data/spec/lib/smooth/templating_spec.rb +23 -0
- data/spec/lib/smooth/util_spec.rb +22 -0
- data/spec/spec_helper.rb +1 -1
- metadata +151 -17
- data/app/helpers/.keep +0 -0
- data/app/mailers/.keep +0 -0
- data/app/models/.keep +0 -0
- data/app/views/.keep +0 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
@@ -0,0 +1,217 @@
|
|
1
|
+
module Smooth
|
2
|
+
class Resource
|
3
|
+
class Router
|
4
|
+
attr_reader :resource,
|
5
|
+
:table,
|
6
|
+
:descriptions,
|
7
|
+
:rules
|
8
|
+
|
9
|
+
def initialize(resource, _options = {})
|
10
|
+
@resource = resource
|
11
|
+
@table = {}
|
12
|
+
@descriptions = {}
|
13
|
+
@rules = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# I may be getting this in a convoluted way
|
17
|
+
# may be easier to build up naturally
|
18
|
+
def interface_documentation
|
19
|
+
descriptions.keys.reduce({}) do |memo, verb|
|
20
|
+
routes = descriptions[verb]
|
21
|
+
routes.each do |_|
|
22
|
+
pattern, description = _
|
23
|
+
memo["#{ verb.to_s.upcase } #{ pattern }"] = description
|
24
|
+
end
|
25
|
+
|
26
|
+
memo
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def route_table
|
31
|
+
@route_table ||= route_patterns_table.reduce({}) do |memo, p|
|
32
|
+
route_name, details = p
|
33
|
+
memo[route_name] = details[:pattern]
|
34
|
+
memo
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def expand_routes(from_attributes = {})
|
39
|
+
route_patterns_table.reduce({}) do |memo, p|
|
40
|
+
route_name, details = p
|
41
|
+
memo[route_name] = Smooth.util.expand_url_template(details[:template], from_attributes)
|
42
|
+
memo
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def route_patterns_table
|
47
|
+
return @route_patterns_table if @route_patterns_table
|
48
|
+
|
49
|
+
@route_patterns_table = rules.flatten.compact.reduce({}) do |memo, rule|
|
50
|
+
memo.tap do
|
51
|
+
name = rule[:name]
|
52
|
+
pattern = rule[:pattern]
|
53
|
+
template = rule[:template]
|
54
|
+
|
55
|
+
memo[name] = {
|
56
|
+
pattern: pattern,
|
57
|
+
template: template,
|
58
|
+
variables: Array(template.variables)
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def patterns
|
65
|
+
rules.flatten.compact.map { |r| r.fetch(:pattern) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def uri_templates
|
69
|
+
rules.flatten.compact.map { |r| r.fetch(:template) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def apply_to(sinatra)
|
73
|
+
router = self
|
74
|
+
|
75
|
+
user_finder = resource.api.method(:lookup_current_user).to_proc
|
76
|
+
policy_finder = resource.api.method(:lookup_policy).to_proc
|
77
|
+
|
78
|
+
router.rules.each do |_|
|
79
|
+
options, _ = _
|
80
|
+
|
81
|
+
handler = methods_table.method(options[:name])
|
82
|
+
|
83
|
+
sinatra.send options[:method], options[:pattern] do |*args|
|
84
|
+
begin
|
85
|
+
request = {
|
86
|
+
headers: headers,
|
87
|
+
params: params,
|
88
|
+
user: user_finder.call(params, headers),
|
89
|
+
policy: policy_finder.call(params, headers),
|
90
|
+
args: args
|
91
|
+
}
|
92
|
+
rescue => exception
|
93
|
+
halt 500, {}, { error: exception.message, backtrace: exception.backtrace, stage: 'request' }.to_json
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
response = handler.call(request.to_mash)
|
98
|
+
|
99
|
+
body response.body
|
100
|
+
headers response.headers
|
101
|
+
status response.status
|
102
|
+
rescue => exception
|
103
|
+
halt 500, {}, { error: exception.message, backtrace: exception.backtrace, stage: 'response' }.to_json
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def build_methods_table
|
110
|
+
router = self
|
111
|
+
|
112
|
+
@methods_table_class = Class.new do
|
113
|
+
|
114
|
+
k = self
|
115
|
+
|
116
|
+
router.rules.each do |_|
|
117
|
+
options, block = _
|
118
|
+
method_name = options.fetch(:name)
|
119
|
+
k.send :define_method, method_name, (block || router.lookup_handler_for(options[:method], options[:to]))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def counter
|
125
|
+
@counter ||= 0
|
126
|
+
@counter += 1
|
127
|
+
end
|
128
|
+
|
129
|
+
def methods_table
|
130
|
+
@methods_table ||= (@methods_table_class || build_methods_table).new
|
131
|
+
end
|
132
|
+
|
133
|
+
def desc(description, *_args)
|
134
|
+
descriptions[:current] = description
|
135
|
+
end
|
136
|
+
|
137
|
+
Verbs = {
|
138
|
+
get: :get,
|
139
|
+
show: :get,
|
140
|
+
put: :put,
|
141
|
+
patch: :put,
|
142
|
+
create: :post,
|
143
|
+
delete: :delete,
|
144
|
+
destroy: :destroy,
|
145
|
+
options: :options,
|
146
|
+
post: :post
|
147
|
+
}
|
148
|
+
|
149
|
+
def method_missing(meth, *args, &block)
|
150
|
+
if Verbs.keys.include?(meth.to_sym)
|
151
|
+
pattern = args.shift
|
152
|
+
define_route(meth, pattern, *args, &block)
|
153
|
+
else
|
154
|
+
super
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def define_route(request_method, route_pattern, *args, &block)
|
159
|
+
request_method = Verbs.fetch(request_method.to_sym, :get)
|
160
|
+
bucket = table[request_method] ||= {}
|
161
|
+
options = args.extract_options!
|
162
|
+
|
163
|
+
name = options.fetch(:as, "#{ request_method }_#{ counter }")
|
164
|
+
|
165
|
+
describe_route(request_method, route_pattern)
|
166
|
+
|
167
|
+
rules << bucket[route_pattern] = [
|
168
|
+
options.merge(name: name, method: request_method, args: args, pattern: route_pattern, template: Smooth.util.uri_template(route_pattern)),
|
169
|
+
block
|
170
|
+
]
|
171
|
+
end
|
172
|
+
|
173
|
+
def describe_route(request_method, route_pattern)
|
174
|
+
documentation = descriptions[request_method] ||= {}
|
175
|
+
|
176
|
+
if description = descriptions[:current]
|
177
|
+
documentation[route_pattern] = description
|
178
|
+
descriptions.delete(:current)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Allows for a configuration syntax like
|
183
|
+
#
|
184
|
+
# routes do
|
185
|
+
# get "/books", :to => :query
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
# the lookup_handler_for method will attempt to
|
189
|
+
# discern which object is best suited to handle the
|
190
|
+
# request based on the http verb and the signifier
|
191
|
+
def lookup_handler_for(method, signifier)
|
192
|
+
method = method.to_sym
|
193
|
+
signifier = signifier.to_sym
|
194
|
+
|
195
|
+
resource = self.resource
|
196
|
+
|
197
|
+
case
|
198
|
+
|
199
|
+
when method == :get && signifier == :query
|
200
|
+
->(req) { resource.fetch(:query, :default).respond_to_request(req) }
|
201
|
+
|
202
|
+
when (method == :show || method == :get) && signifier == :show
|
203
|
+
->(req) { resource.fetch(:query, :default).respond_to_find_request(req) }
|
204
|
+
|
205
|
+
when method == :get
|
206
|
+
->(req) { resource.fetch(:query, signifier).respond_to_request(req) }
|
207
|
+
|
208
|
+
# Mutation Methods
|
209
|
+
when method == :put || method == :post || method == :delete
|
210
|
+
->(req) { resource.fetch(:command, signifier).respond_to_request(req) }
|
211
|
+
else
|
212
|
+
->(req) { Smooth::ErrorResponse.new('Unable to find matching route', req) }
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Smooth
|
2
|
+
class Resource
|
3
|
+
module Templating
|
4
|
+
FakerGroups = %w(
|
5
|
+
Address Lorem Color Company Food HipterIpsum Internet Job Name Movie PhoneNumber Product Unit Vehicle Venue Skill
|
6
|
+
)
|
7
|
+
|
8
|
+
def self.fakers
|
9
|
+
FakerGroups.flat_map do |group|
|
10
|
+
prefix = group.to_s.underscore.downcase
|
11
|
+
space = Faker.const_get(group.to_sym) rescue nil
|
12
|
+
|
13
|
+
if space && space.class == Module
|
14
|
+
(space.methods - Object.methods - [:k, :underscore]).map { |m| "#{prefix}.#{m}" }
|
15
|
+
end
|
16
|
+
end.compact.uniq
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_from_template(name = nil, *args, &block)
|
20
|
+
if name.is_a?(Hash)
|
21
|
+
args.unshift(name)
|
22
|
+
name = @template_name
|
23
|
+
end
|
24
|
+
FactoryGirl.create(name || @template_name, *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_from_template(name = nil, *args, &block)
|
28
|
+
if name.is_a?(Hash)
|
29
|
+
args.unshift(name)
|
30
|
+
name = @template_name
|
31
|
+
end
|
32
|
+
|
33
|
+
FactoryGirl.build(name || @template_name, *args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def template(name = nil, *args, &block)
|
37
|
+
options = args.extract_options!
|
38
|
+
|
39
|
+
if name.nil?
|
40
|
+
name = model_class.table_name.singularize.to_sym
|
41
|
+
@template_name ||= name
|
42
|
+
end
|
43
|
+
|
44
|
+
options[:class] ||= model_class
|
45
|
+
|
46
|
+
FactoryGirl.define do
|
47
|
+
factory(name.to_sym, options, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def template_registered?(name = nil)
|
52
|
+
name ||= model_class.table_name.singularize.to_sym
|
53
|
+
!!(FactoryGirl.factory_by_name(name) rescue nil)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Just allows us to wrap template definitions
|
57
|
+
def templates(&block)
|
58
|
+
instance_eval(&block)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Smooth
|
2
|
+
class Response
|
3
|
+
attr_reader :outcome, :serializer_options
|
4
|
+
|
5
|
+
attr_accessor :request_headers, :serializer, :event_namespace, :command_action, :success, :object, :serializer_klass, :current_user
|
6
|
+
|
7
|
+
def initialize(outcome, serializer_options = {})
|
8
|
+
@outcome = outcome
|
9
|
+
@serializer_options = serializer_options
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_rack
|
13
|
+
[status, headers, [body]]
|
14
|
+
end
|
15
|
+
|
16
|
+
def headers
|
17
|
+
{
|
18
|
+
'Content-Type' => 'application/json'
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def options
|
23
|
+
if success? && serializer
|
24
|
+
(@serializer_options || {}).merge(serializer: serializer, scope: current_user)
|
25
|
+
else
|
26
|
+
@serializer_options.merge(scope: current_user)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def body
|
31
|
+
serializer.new(object, options).to_json(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def object
|
35
|
+
@object || begin
|
36
|
+
if success?
|
37
|
+
outcome.result
|
38
|
+
else
|
39
|
+
outcome.errors.message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def success?
|
45
|
+
@success || (outcome && outcome.success?)
|
46
|
+
end
|
47
|
+
|
48
|
+
def status
|
49
|
+
case
|
50
|
+
when success?
|
51
|
+
200
|
52
|
+
else
|
53
|
+
400
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class ErrorResponse < Response
|
59
|
+
def initialize(error_message, _request_object, *_args)
|
60
|
+
@error_message = error_message
|
61
|
+
end
|
62
|
+
|
63
|
+
def success?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def body
|
68
|
+
{
|
69
|
+
error: error_message
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/smooth/serializer.rb
CHANGED
@@ -3,12 +3,50 @@ module Smooth
|
|
3
3
|
include Smooth::Documentation
|
4
4
|
|
5
5
|
class_attribute :attribute_descriptions,
|
6
|
-
:relationship_descriptions
|
6
|
+
:relationship_descriptions,
|
7
|
+
:resource_route_variables
|
7
8
|
|
8
9
|
self.attribute_descriptions = {}.to_mash
|
9
10
|
self.relationship_descriptions = {}.to_mash
|
10
11
|
|
11
|
-
|
12
|
+
# WIP
|
13
|
+
# Need to determine how to access the serialized version
|
14
|
+
# as it exists in the context of the serializer instance
|
15
|
+
def expand_routes(*slice)
|
16
|
+
expanded = parent_resource.expand_routes(route_variables)
|
17
|
+
|
18
|
+
unless slice.empty?
|
19
|
+
expanded = expanded.send(:slice, *slice)
|
20
|
+
end
|
21
|
+
|
22
|
+
expanded.transform_keys do |key|
|
23
|
+
"#{ key }_url"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def route_variables
|
28
|
+
serializer = self
|
29
|
+
|
30
|
+
self.class.route_variables.reduce({}) do |memo, var|
|
31
|
+
value = case
|
32
|
+
when serializer.respond_to?(var)
|
33
|
+
serializer.send(var)
|
34
|
+
when serializer.object.respond_to?(var)
|
35
|
+
serializer.object.send(var)
|
36
|
+
else
|
37
|
+
serializer.read_attribute_for_serialization(var)
|
38
|
+
end
|
39
|
+
|
40
|
+
memo[var] = value
|
41
|
+
memo
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.route_variables
|
46
|
+
@resource_route_variables ||= parent_resource.router.route_patterns_table.map { |p| _, h = p; h[:variables] }.flatten.compact.uniq
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.method_added(method_name)
|
12
50
|
if documented = inline_description
|
13
51
|
attribute_descriptions[method_name.to_sym] = documented
|
14
52
|
end
|
@@ -22,7 +60,7 @@ module Smooth
|
|
22
60
|
schema[:associations]
|
23
61
|
end
|
24
62
|
|
25
|
-
def self.configure
|
63
|
+
def self.configure(options, resource = nil)
|
26
64
|
resource ||= Smooth.current_resource
|
27
65
|
klass = define_or_open(options, resource)
|
28
66
|
|
@@ -38,22 +76,53 @@ module Smooth
|
|
38
76
|
base = Smooth.serializer
|
39
77
|
|
40
78
|
name = options.name
|
41
|
-
name = nil if name ==
|
79
|
+
name = nil if name == 'Default'
|
80
|
+
|
81
|
+
klass = "#{ resource.model_class }#{ name }".singularize + 'Serializer'
|
42
82
|
|
43
|
-
klass =
|
83
|
+
klass = klass.gsub(/\s+/, '')
|
44
84
|
|
45
85
|
if serializer_klass = Object.const_get(klass) rescue nil
|
46
86
|
return serializer_klass
|
47
87
|
end
|
48
88
|
|
49
|
-
|
89
|
+
parent_klass = Class.new(base)
|
90
|
+
|
91
|
+
parent_klass.belongs_to_resource(resource)
|
92
|
+
|
93
|
+
begin
|
94
|
+
Object.const_set(klass, parent_klass)
|
95
|
+
rescue => ex
|
96
|
+
puts ex.message
|
97
|
+
puts "Error setting #{ klass } #{ base }. klass is a #{ klass.class }"
|
98
|
+
end
|
99
|
+
|
100
|
+
parent_klass
|
50
101
|
end
|
51
102
|
|
52
|
-
|
103
|
+
class_attribute :parent_resource
|
104
|
+
|
105
|
+
def parent_resource
|
106
|
+
self.class.parent_resource
|
107
|
+
end
|
108
|
+
|
109
|
+
def parent_api
|
110
|
+
self.class.parent_api
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.belongs_to_resource(resource)
|
114
|
+
self.parent_resource = resource
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.parent_api
|
118
|
+
parent_resource.api
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.documentation_for_attribute(attribute)
|
53
122
|
attribute_descriptions[attribute.to_sym]
|
54
123
|
end
|
55
124
|
|
56
|
-
def self.documentation_for_association
|
125
|
+
def self.documentation_for_association(association)
|
57
126
|
relationship_descriptions[association.to_sym]
|
58
127
|
end
|
59
128
|
|
@@ -61,7 +130,11 @@ module Smooth
|
|
61
130
|
attribute_descriptions.merge(relationship_descriptions).to_mash
|
62
131
|
end
|
63
132
|
|
64
|
-
def self.
|
133
|
+
def self.interface_documentation
|
134
|
+
documentation
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.attribute(attr, options = {})
|
65
138
|
documented = inline_description
|
66
139
|
|
67
140
|
if documented
|
@@ -71,7 +144,13 @@ module Smooth
|
|
71
144
|
super
|
72
145
|
end
|
73
146
|
|
74
|
-
def self.
|
147
|
+
def self.computed(*args, &block)
|
148
|
+
property_name = args.first
|
149
|
+
send(:define_method, property_name, &block)
|
150
|
+
send(:attribute, *args)
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.has_one(attr, options = {})
|
75
154
|
documented = inline_description
|
76
155
|
|
77
156
|
if documented
|
@@ -81,7 +160,7 @@ module Smooth
|
|
81
160
|
super
|
82
161
|
end
|
83
162
|
|
84
|
-
def self.has_many
|
163
|
+
def self.has_many(attr, options = {})
|
85
164
|
documented = inline_description
|
86
165
|
|
87
166
|
if documented
|
@@ -90,5 +169,17 @@ module Smooth
|
|
90
169
|
|
91
170
|
super
|
92
171
|
end
|
172
|
+
|
173
|
+
def self.return_ids_for_relationships!
|
174
|
+
@returns_ids_for_relationships = true
|
175
|
+
embed :ids
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.returns_ids_for_relationships?
|
179
|
+
@returns_ids_for_relationships == true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class ArraySerializer < ActiveModel::ArraySerializer
|
93
184
|
end
|
94
185
|
end
|