This repository has been archived by the owner on Jun 24, 2020. It is now read-only.
forked from hashrocket/decent_exposure
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sketch.rb
323 lines (255 loc) · 5.97 KB
/
sketch.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
class DecentExposure::Naming
attr_accessor :name
def initialize(name)
self.name = name
end
alias original name
def plural
# MAGIC, MAGIC, MAGIC!!
end
def singular
end
def model_name
end
def model
const_get(model_name)
end
def to_sym
name.to_sym
end
end
class DecentExposure::Strategizer
attr_accessor :framework, :orm
def initialize(framework,orm,&blk)
if block_given?
yield
else
self.configured_framework = framework
self.configured_orm = orm
end
end
def orm
configured_orm || DecentExposure::ActiveRecordAdapter
end
def framework
configured_framework || DecentExposure::RailsAdapter
end
def orm=(orm)
self.configured_framework = strategy_class(orm)
end
def framework=(framework)
self.configured_framework = strategy_class(framework)
end
private
def strategy_class(kind)
const_get("DecentExposure::#{strategize(kind)}")
end
def strategize(kind)
[classify(kind),'Strategy'].join
end
def classify(kind)
kind.to_s.split('_').map{|s| s =~ /^(\w)(.*)/; [$1.upcase,$2].join }.join
end
end
module DecentExposure::Config
class_attribute :_strategizer
def self.decent_config(framework=nil,orm=nil,&blk)
self._strategizer = DecentExposure::Strategizer.new(framework,orm,&blk)
self.orm_strategy = _strategizer.orm
end
end
module DecentExposure::Expose
attr_accessor :exposure
def self.expose(name)
self.exposure = DecentExposure::Exposure.new(self,name)
define_method name do
_resources[name] ||= exposure.call
end
framework.after_expose(name)
end
def _resources
@_resources || {}
end
end
class DecentExposure::Exposure
attr_accessor :attributes
attr_reader :name
def initialize(controller, name)
self.controller = controller
self.name = name
end
def call
if existing?
orm.retrieve
else
orm.instantiate
end
end
def name=(v)
self.name = DecentExposure::Naming.new(name)
end
def existing?
!!id
end
def id
# #{name}_id, id or nil
end
def orm
@orm ||= _strategizer.orm_strategy.new(controller,name)
end
def framework
@framework ||= _strategizer.framework_strategy.new(controller,name)
end
end
class DecentExposure::FrameworkStrategy
def idempotent?
raise "Implement in Subclass"
end
alias attributes idempotent?
end
class DecentExposure::ORMStrategy
attr_accessor :name
def initialize(controller, name)
self.controller = controller
self.name = name
end
def scope
collection_resource || name.model.send(scoping_method)
end
def collection_resource
if controller.respond_to?(name.plural)
send(name.plural)
end
end
def proxy
if name.plural?
scope
else
name.model
end
end
def instantiate
raise "Implement in Subclass"
end
alias retrieve instantiate
end
class DecentExposure::RailsStrategy < DecentExposure::FrameworkStrategy
attr_accessor :controller, :name
def initialize(controller,name)
self.controller = controller
self.name = name
end
def idempotent?
controller.request.get?
end
def attributes
controller.params[name]
end
def after_expose(name)
controller.hide_action name
controller.helper_method name
end
end
class DecentExposure::ActiveRecordStrategy < DecentExposure::ORMStrategy
def instantiate
proxy.new(framework.attributes)
end
def retrieve(id)
proxy.find(id).tap do |r|
r.attributes = framework.attributes unless framework.idempotent?
end
end
def scoping_method
:scoped
end
end
class ApplicationController
decent_config(:sinatra,:datamapper)
decent_config do
framework :sinatra # SinatraStrategy
orm :datamapper
end
end
decent_strategy(:whatchamacallit) do
model { ThingModel }
finder
end
class WhatchamacallitStrategy
end
class Controller
expose(:things)
expose(:whatever, model: :thing)
expose(:whatever, model: :thing, :finder: :find_by_thing, scope: :things)
# filtering parameters
expose(:whatever, attributes: [:ok, :also_ok])
# using a custom / filtered set of parameters
expose(:whatever, params: :whatever_params)
def whatever_params
attrs = params[:whatever] || {}
if current_user.admin?
attrs.slice(:ok, :also_ok, :ok_for_admin)
else
attrs.slice(:ok, :also_ok)
end
end
# using the default behavior of decent_exposure with an app specific twist
expose(:whatever, orm: :data_mapper) { app_specific(framework.execute_default) }
def app_specific(object)
AppSpecific.new(object)
end
# end
exposure(:example) do
orm :mem_cache
model { Thing }
finder :find_by_thing
scope { model.scoped.further }
end
exposure(:affiliations) do
scope { Affiliation.unscoped }
end
# uses the :affiliations exposure
expose(:affiliations) do
Decorator.new(framework.execute_default)
end
# Decorator.new(Affiliation.unscoped.find(params[:id]))
exposure(:active_affiliations) do
scope { Affiliation.unscoped.active }
end
expose(:affiliations, exposure: :active_affiliations) do
framework.execute_default.paginate(params[:page])
end
# Affiliation.unscoped.active.find(params[:id]).paginate(params[:page])
# avoiding conditionals
# before
expose(:whatever) do
if controller.action == :foo
SomethingTerrible.new
else
SomethingTerrible.new(params[:page])
end
end
# yields to an instance of DecentExposure
exposure(:default) do
orm :active_record
framework :rails
model { orm.model_class }
finder :where
scope -> {}
end
exposure(:default, with: IndecentExposure) do
orm :active_record
framework :rails
model { orm.model_class }
finder :where
scope -> {}
end
# after
exposure(:something) do
condition { controller.action == :foo }
truthy { SomethingTerrible.new }
falsey { SomethingTerrible.active.new }
scope { Affiliation.unscoped.active }
end
expose(:whatever, exposure: :something)
# end
end