dao 2.2.3 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +68 -113
- data/TODO +3 -9
- data/a.rb +25 -0
- data/dao.gemspec +70 -14
- data/lib/dao.rb +8 -8
- data/lib/dao/api.rb +1 -0
- data/lib/dao/api/context.rb +48 -23
- data/lib/dao/api/dsl.rb +1 -1
- data/lib/dao/api/interfaces.rb +149 -117
- data/lib/dao/api/modes.rb +24 -23
- data/lib/dao/api/routes.rb +9 -0
- data/lib/dao/data.rb +9 -2
- data/lib/dao/errors.rb +15 -11
- data/lib/dao/form.rb +46 -37
- data/lib/dao/interface.rb +1 -1
- data/lib/dao/mode.rb +45 -20
- data/lib/dao/params.rb +35 -53
- data/lib/dao/path.rb +6 -9
- data/lib/dao/rails/lib/generators/dao/templates/api.rb +1 -1
- data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +16 -0
- data/lib/dao/result.rb +26 -133
- data/lib/dao/route.rb +87 -0
- data/lib/dao/status.rb +96 -94
- data/lib/dao/support.rb +5 -3
- data/lib/dao/validations.rb +46 -442
- data/lib/dao/validations/base.rb +68 -0
- data/lib/dao/validations/common.rb +463 -0
- data/test/dao_test.rb +214 -33
- metadata +20 -112
- data/lib/dao/rails/app/api.rb +0 -55
- data/lib/dao/rails/app/controllers/api_controller.rb +0 -99
- data/sample/rails_app/Gemfile +0 -33
- data/sample/rails_app/Gemfile.lock +0 -88
- data/sample/rails_app/README +0 -1
- data/sample/rails_app/Rakefile +0 -7
- data/sample/rails_app/app/api.rb +0 -55
- data/sample/rails_app/app/controllers/api_controller.rb +0 -99
- data/sample/rails_app/app/controllers/application_controller.rb +0 -3
- data/sample/rails_app/app/helpers/application_helper.rb +0 -2
- data/sample/rails_app/app/views/layouts/application.html.erb +0 -14
- data/sample/rails_app/config.ru +0 -4
- data/sample/rails_app/config/application.rb +0 -51
- data/sample/rails_app/config/boot.rb +0 -13
- data/sample/rails_app/config/database.yml +0 -22
- data/sample/rails_app/config/environment.rb +0 -5
- data/sample/rails_app/config/environments/development.rb +0 -26
- data/sample/rails_app/config/environments/production.rb +0 -49
- data/sample/rails_app/config/environments/test.rb +0 -35
- data/sample/rails_app/config/initializers/backtrace_silencers.rb +0 -7
- data/sample/rails_app/config/initializers/inflections.rb +0 -10
- data/sample/rails_app/config/initializers/mime_types.rb +0 -5
- data/sample/rails_app/config/initializers/secret_token.rb +0 -7
- data/sample/rails_app/config/initializers/session_store.rb +0 -8
- data/sample/rails_app/config/locales/en.yml +0 -5
- data/sample/rails_app/config/routes.rb +0 -62
- data/sample/rails_app/db/development.sqlite3 +0 -0
- data/sample/rails_app/db/seeds.rb +0 -7
- data/sample/rails_app/doc/README_FOR_APP +0 -2
- data/sample/rails_app/log/development.log +0 -27
- data/sample/rails_app/log/production.log +0 -0
- data/sample/rails_app/log/server.log +0 -0
- data/sample/rails_app/log/test.log +0 -0
- data/sample/rails_app/pubic/javascripts/dao.js +0 -148
- data/sample/rails_app/public/404.html +0 -26
- data/sample/rails_app/public/422.html +0 -26
- data/sample/rails_app/public/500.html +0 -26
- data/sample/rails_app/public/favicon.ico +0 -0
- data/sample/rails_app/public/images/rails.png +0 -0
- data/sample/rails_app/public/index.html +0 -239
- data/sample/rails_app/public/javascripts/application.js +0 -2
- data/sample/rails_app/public/javascripts/controls.js +0 -965
- data/sample/rails_app/public/javascripts/dragdrop.js +0 -974
- data/sample/rails_app/public/javascripts/effects.js +0 -1123
- data/sample/rails_app/public/javascripts/prototype.js +0 -6001
- data/sample/rails_app/public/javascripts/rails.js +0 -175
- data/sample/rails_app/public/robots.txt +0 -5
- data/sample/rails_app/script/rails +0 -6
- data/sample/rails_app/test/performance/browsing_test.rb +0 -9
- data/sample/rails_app/test/test_helper.rb +0 -13
data/lib/dao/api.rb
CHANGED
data/lib/dao/api/context.rb
CHANGED
@@ -1,38 +1,63 @@
|
|
1
1
|
module Dao
|
2
2
|
class Context
|
3
|
-
Attrs = %w( api interface params result
|
4
|
-
Attrs.each{|attr| attr_accessor(attr)}
|
3
|
+
Attrs = %w( api route path interface method args status errors params result data form validations )
|
5
4
|
|
6
|
-
|
5
|
+
Attrs.each{|a| attr_accessor(a)}
|
6
|
+
|
7
|
+
def Context.attrs
|
8
|
+
Attrs
|
9
|
+
end
|
10
|
+
|
11
|
+
def Context.for(api, route, path, interface, params, *args)
|
12
|
+
# setup
|
13
|
+
#
|
7
14
|
options = Dao.options_for!(args)
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
params
|
14
|
-
result = Result.new(:api => api, :interface => interface, :params => params)
|
15
|
-
params.result = result
|
16
|
+
parsed_params = Dao.parse(path, params, options)
|
17
|
+
|
18
|
+
result = Result.new(:mode => api.mode)
|
19
|
+
params = result.params
|
20
|
+
params.update(parsed_params)
|
16
21
|
|
17
22
|
method = interface.method.bind(api)
|
18
23
|
args = [params, result].slice(0, method.arity)
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
# build the context
|
26
|
+
#
|
27
|
+
context = new
|
28
|
+
context.api = api
|
29
|
+
context.interface = interface
|
30
|
+
context.route = route
|
31
|
+
context.path = path
|
32
|
+
context.method = method
|
33
|
+
context.args = args
|
34
|
+
context.status = Status.default
|
35
|
+
context.errors = Errors.new
|
27
36
|
|
28
|
-
|
29
|
-
|
37
|
+
context.result = result
|
38
|
+
context.data = result.data
|
39
|
+
|
40
|
+
context.params = params
|
41
|
+
context.form = params.form
|
42
|
+
context.validations = params.validations
|
43
|
+
|
44
|
+
# wire up shared state
|
45
|
+
#
|
46
|
+
result.route = context.route
|
47
|
+
result.path = context.path
|
48
|
+
result.status = context.status
|
49
|
+
result.errors = context.errors
|
50
|
+
|
51
|
+
params.route = context.route
|
52
|
+
params.path = context.path
|
53
|
+
params.status = context.status
|
54
|
+
params.errors = context.errors
|
55
|
+
|
56
|
+
context
|
30
57
|
end
|
31
58
|
|
32
|
-
def
|
33
|
-
|
34
|
-
send("#{ key }=", val)
|
35
|
-
end
|
59
|
+
def call
|
60
|
+
method.call(*args)
|
36
61
|
end
|
37
62
|
end
|
38
63
|
end
|
data/lib/dao/api/dsl.rb
CHANGED
@@ -19,7 +19,7 @@ module Dao
|
|
19
19
|
raise "no interface for #{ docs.inspect }" unless docs.empty?
|
20
20
|
end
|
21
21
|
|
22
|
-
%w( interface doc docs description desc ).each do |method|
|
22
|
+
%w( interface call doc docs description desc ).each do |method|
|
23
23
|
module_eval <<-__, __FILE__, __LINE__ - 1
|
24
24
|
|
25
25
|
def #{ method }(*args, &block)
|
data/lib/dao/api/interfaces.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Dao
|
2
2
|
class Api
|
3
|
+
# class methods
|
4
|
+
#
|
3
5
|
class << Api
|
4
6
|
def interfaces
|
5
7
|
@interfaces ||= Map.new
|
@@ -9,23 +11,24 @@ module Dao
|
|
9
11
|
api = self
|
10
12
|
path = Path.new(path)
|
11
13
|
|
14
|
+
route = routes.add(path) if Route.like?(path)
|
15
|
+
|
12
16
|
method =
|
13
17
|
module_eval{
|
14
18
|
define_method(path + '/interface', &block)
|
15
19
|
instance_method(path + '/interface')
|
16
20
|
}
|
17
21
|
|
18
|
-
|
19
22
|
interface = Interface.new(
|
20
23
|
'api' => api,
|
21
24
|
'path' => path,
|
25
|
+
'route' => route,
|
22
26
|
'method' => method,
|
23
27
|
'doc' => docs.pop
|
24
28
|
)
|
25
29
|
|
26
30
|
interfaces[path] = interface
|
27
31
|
end
|
28
|
-
|
29
32
|
alias_method('call', 'interface')
|
30
33
|
|
31
34
|
def description(string)
|
@@ -51,197 +54,226 @@ module Dao
|
|
51
54
|
def index
|
52
55
|
index = Map.new
|
53
56
|
interfaces.each do |path, interface|
|
54
|
-
index[path] = interface.doc || {'description' =>
|
57
|
+
index[path] = interface.doc || {'description' => ''}
|
55
58
|
end
|
56
59
|
index
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
63
|
+
# instance methods
|
64
|
+
#
|
65
|
+
|
66
|
+
|
67
|
+
# call support
|
68
|
+
#
|
60
69
|
def call(path = '/index', params = {}, options = {})
|
61
70
|
api = self
|
62
71
|
path = Path.new(path)
|
63
|
-
interface = interfaces[path]
|
72
|
+
interface = interfaces[path] ### interfaces.by_path(path)
|
73
|
+
route = nil
|
74
|
+
|
75
|
+
unless interface
|
76
|
+
route = route_for(path)
|
77
|
+
interface = interfaces[route]
|
78
|
+
end
|
64
79
|
|
65
80
|
unless interface
|
66
81
|
return index if path == '/index'
|
67
82
|
raise(NameError, "NO SUCH INTERFACE: #{ path }")
|
68
83
|
end
|
69
84
|
|
70
|
-
|
71
|
-
|
72
|
-
|
85
|
+
if route
|
86
|
+
params.update(route.params_for(path))
|
87
|
+
path = route.path_for(params)
|
88
|
+
else
|
89
|
+
if Route.like?(path)
|
90
|
+
route = Route.new(path)
|
91
|
+
path = route.path_for(params)
|
92
|
+
end
|
93
|
+
end
|
73
94
|
|
74
|
-
context = Context.
|
75
|
-
:api => api,
|
76
|
-
:interface => interface,
|
77
|
-
:params => params
|
78
|
-
)
|
95
|
+
context = Context.for(api, route, path, interface, params, options)
|
79
96
|
|
80
97
|
callstack(context) do
|
81
|
-
catching(:result)
|
98
|
+
catching(:result) do
|
99
|
+
context.call()
|
100
|
+
end
|
82
101
|
end
|
83
102
|
|
84
103
|
context.result
|
85
104
|
end
|
86
105
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
106
|
+
# lookup a route
|
107
|
+
#
|
108
|
+
def route_for(*args)
|
109
|
+
self.class.routes.match(*args)
|
91
110
|
end
|
92
111
|
|
93
|
-
|
94
|
-
|
112
|
+
# context support
|
113
|
+
#
|
114
|
+
def callstack(context = nil, &block)
|
115
|
+
@callstack ||= []
|
116
|
+
|
117
|
+
if block and context
|
118
|
+
begin
|
119
|
+
@callstack.push(context)
|
120
|
+
return block.call()
|
121
|
+
ensure
|
122
|
+
@callstack.pop
|
123
|
+
end
|
124
|
+
else
|
125
|
+
@callstack
|
126
|
+
end
|
95
127
|
end
|
96
128
|
|
97
129
|
def context
|
98
130
|
callstack.last || raise('no context!')
|
99
131
|
end
|
100
132
|
|
101
|
-
def
|
102
|
-
|
133
|
+
def context?
|
134
|
+
!!callstack.last
|
103
135
|
end
|
104
136
|
|
105
|
-
def
|
106
|
-
|
137
|
+
def catching(label = :result, &block)
|
138
|
+
@catching ||= []
|
139
|
+
|
140
|
+
if block
|
141
|
+
begin
|
142
|
+
@catching.push(label)
|
143
|
+
catch(label, &block)
|
144
|
+
ensure
|
145
|
+
@catching.pop
|
146
|
+
end
|
147
|
+
else
|
148
|
+
@catching.last
|
149
|
+
end
|
107
150
|
end
|
108
151
|
|
109
|
-
def
|
110
|
-
result
|
152
|
+
def return!(*value)
|
153
|
+
throw(:result, *value)
|
111
154
|
end
|
112
155
|
|
113
|
-
def
|
114
|
-
|
156
|
+
def catching_results(&block)
|
157
|
+
catching(:result, &block)
|
115
158
|
end
|
116
159
|
|
117
|
-
def
|
118
|
-
|
160
|
+
def catching?
|
161
|
+
catching
|
119
162
|
end
|
120
163
|
|
121
|
-
def
|
122
|
-
|
123
|
-
if hash.empty?
|
124
|
-
value = args.pop
|
125
|
-
key = args
|
126
|
-
hash = {key => value}
|
127
|
-
end
|
128
|
-
data.apply(hash)
|
164
|
+
def catching_results?
|
165
|
+
catching == :result
|
129
166
|
end
|
130
167
|
|
131
|
-
|
132
|
-
|
168
|
+
# delgate some methods to the context
|
169
|
+
#
|
170
|
+
Context.attrs.each do |method|
|
171
|
+
module_eval <<-__, __FILE__, __LINE__
|
172
|
+
def #{ method }(*args)
|
173
|
+
context.send(#{ method.inspect }, *args)
|
174
|
+
end
|
175
|
+
__
|
133
176
|
end
|
134
177
|
|
135
|
-
def status
|
136
|
-
status(*args
|
178
|
+
def status(*args)
|
179
|
+
context.status.update(*args) unless args.empty?
|
180
|
+
context.status
|
181
|
+
end
|
182
|
+
def status!(*args)
|
183
|
+
status.update(*args)
|
137
184
|
return!
|
138
185
|
end
|
139
186
|
|
140
187
|
def data(*args)
|
141
|
-
|
142
|
-
|
143
|
-
else
|
144
|
-
result.data.replace(*args)
|
145
|
-
end
|
188
|
+
context.data.replace(*args) unless args.empty?
|
189
|
+
context.data
|
146
190
|
end
|
147
|
-
|
148
191
|
def data!(*args)
|
149
|
-
|
192
|
+
data(*args)
|
150
193
|
valid!
|
151
194
|
end
|
152
195
|
|
153
|
-
def
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
def replace(*args, &block)
|
158
|
-
data.replace(*args, &block)
|
159
|
-
end
|
160
|
-
|
161
|
-
def validations
|
162
|
-
result.validations
|
196
|
+
def params!(*args)
|
197
|
+
params.replace(*args)
|
198
|
+
valid!
|
163
199
|
end
|
164
200
|
|
165
|
-
def
|
166
|
-
result.
|
201
|
+
def error!
|
202
|
+
result.error!
|
167
203
|
end
|
168
204
|
|
169
|
-
|
170
|
-
|
205
|
+
# delegate some methods to the params
|
206
|
+
#
|
207
|
+
Validations::Mixin.list.each do |method|
|
208
|
+
module_eval <<-__, __FILE__, __LINE__
|
209
|
+
def #{ method }(*args)
|
210
|
+
params.send(#{ method.inspect }, *args)
|
211
|
+
end
|
212
|
+
__
|
171
213
|
end
|
172
214
|
|
173
|
-
|
174
|
-
|
215
|
+
# misc
|
216
|
+
#
|
217
|
+
def index
|
218
|
+
self.class.index
|
175
219
|
end
|
176
220
|
|
177
|
-
def
|
178
|
-
|
221
|
+
def interfaces
|
222
|
+
self.class.interfaces
|
179
223
|
end
|
180
224
|
|
181
|
-
def
|
182
|
-
|
225
|
+
def respond_to?(*args)
|
226
|
+
super(*args) || super(Path.absolute_path_for(*args))
|
183
227
|
end
|
184
228
|
|
185
|
-
|
186
|
-
|
187
|
-
def
|
188
|
-
|
189
|
-
end
|
229
|
+
# immediate parameter parsing support
|
230
|
+
#
|
231
|
+
def parameter(*args, &block)
|
232
|
+
options = Map.options_for!(args)
|
190
233
|
|
191
|
-
=
|
192
|
-
def set(*args, &block)
|
193
|
-
result.data.set(*args, &block)
|
194
|
-
end
|
234
|
+
keys = args + Array(options[:keys]) + Array(options[:or])
|
195
235
|
|
196
|
-
|
197
|
-
params.data.get(*args, &block)
|
198
|
-
end
|
199
|
-
=end
|
236
|
+
raise(ArgumentError, 'no keys') if keys.empty?
|
200
237
|
|
201
|
-
|
202
|
-
|
238
|
+
blank = Object.new.freeze
|
239
|
+
value = blank
|
203
240
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
ensure
|
209
|
-
@callstack.pop
|
241
|
+
keys.each do |key|
|
242
|
+
if params.has?(key)
|
243
|
+
value = params.get(key)
|
244
|
+
break unless value.to_s.strip.empty?
|
210
245
|
end
|
211
|
-
else
|
212
|
-
@callstack
|
213
246
|
end
|
214
|
-
end
|
215
247
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
248
|
+
if value == blank
|
249
|
+
message =
|
250
|
+
case options[:error]
|
251
|
+
when nil, false
|
252
|
+
nil
|
253
|
+
when true
|
254
|
+
which = keys.map{|key| Array(key).join('.')}.join(' or ')
|
255
|
+
"#{ which } (parameter is blank)"
|
256
|
+
else
|
257
|
+
message = options[:error].to_s
|
258
|
+
end
|
259
|
+
errors.add(message) if message
|
260
|
+
|
261
|
+
status(options[:status]) if options[:status]
|
262
|
+
return! if options[:return!]
|
228
263
|
end
|
229
|
-
end
|
230
264
|
|
231
|
-
|
232
|
-
catching(:result, &block)
|
233
|
-
end
|
234
|
-
|
235
|
-
def catching?
|
236
|
-
catching
|
265
|
+
value == blank ? nil : value
|
237
266
|
end
|
267
|
+
alias_method('param', 'parameter')
|
238
268
|
|
239
|
-
def
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
269
|
+
def parameter!(*args, &block)
|
270
|
+
options = args.last.is_a?(Hash) ? Map.for(args.pop) : Map.new
|
271
|
+
args.push(options)
|
272
|
+
options[:error] = true unless options.has_key?(:error)
|
273
|
+
options[:return!] = true unless options.has_key?(:return!)
|
274
|
+
options[:status] = 412 unless options.has_key?(:status)
|
275
|
+
parameter(*args, &block)
|
245
276
|
end
|
277
|
+
alias_method('param!', 'parameter!')
|
246
278
|
end
|
247
279
|
end
|