dao 2.1.0 → 2.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -0
- data/TODO +39 -0
- data/dao.gemspec +4 -4
- data/lib/dao.rb +8 -4
- data/lib/dao/active_record.rb +46 -4
- data/lib/dao/api/interfaces.rb +19 -4
- data/lib/dao/data.rb +3 -53
- data/lib/dao/errors.rb +26 -19
- data/lib/dao/exceptions.rb +23 -1
- data/lib/dao/form.rb +55 -11
- data/lib/dao/params.rb +41 -51
- data/lib/dao/presenter.rb +129 -0
- data/lib/dao/rails.rb +49 -1
- data/lib/dao/rails/lib/generators/dao/dao_generator.rb +1 -2
- data/lib/dao/rails/lib/generators/dao/templates/api.rb +1 -1
- data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +25 -31
- data/lib/dao/rails/lib/generators/dao/templates/dao.js +34 -25
- data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +2 -1
- data/lib/dao/result.rb +27 -2
- data/lib/dao/status.rb +10 -2
- data/lib/dao/support.rb +1 -1
- data/lib/dao/validations.rb +143 -8
- data/test/dao_test.rb +56 -1
- metadata +15 -13
data/lib/dao/form.rb
CHANGED
@@ -60,19 +60,19 @@ module Dao
|
|
60
60
|
options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
|
61
61
|
keys = args.flatten
|
62
62
|
|
63
|
-
name = options.delete(:name) || keys.last
|
64
63
|
id = options.delete(:id) || id_for(keys)
|
65
64
|
klass = class_for(keys, options.delete(:class))
|
66
65
|
error = error_for(keys, options.delete(:error))
|
66
|
+
target = options.delete(:for) || id_for(keys)
|
67
67
|
|
68
68
|
content =
|
69
|
-
if block.nil? and !options.has_key?(:content)
|
70
|
-
|
69
|
+
if block.nil? and !options.has_key?(:content)
|
70
|
+
humanize(keys.last)
|
71
71
|
else
|
72
72
|
block ? block.call() : options.delete(:content)
|
73
73
|
end
|
74
74
|
|
75
|
-
label_(options_for(options, :
|
75
|
+
label_(options_for(options, :for => target, :class => klass, :id => id, :data_error => error)){ content }
|
76
76
|
end
|
77
77
|
|
78
78
|
def input(*args, &block)
|
@@ -97,10 +97,14 @@ module Dao
|
|
97
97
|
|
98
98
|
def submit(*args, &block)
|
99
99
|
options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
|
101
|
+
content = block ? block.call : (args.first || 'Submit')
|
102
|
+
|
103
|
+
options[:name] ||= :submit
|
104
|
+
options[:type] ||= :submit
|
105
|
+
options[:value] ||= content
|
106
|
+
|
107
|
+
input_(options_for(options)){}
|
104
108
|
end
|
105
109
|
|
106
110
|
def button(*args)
|
@@ -156,6 +160,13 @@ module Dao
|
|
156
160
|
name = options.delete(:name) || name_for(keys)
|
157
161
|
from = options.delete(:from) || options.delete(:options)
|
158
162
|
|
163
|
+
selected =
|
164
|
+
if options.has_key?(:selected)
|
165
|
+
options.delete(:selected)
|
166
|
+
else
|
167
|
+
value_for(data, keys)
|
168
|
+
end
|
169
|
+
|
159
170
|
id = options.delete(:id) || id_for(keys)
|
160
171
|
klass = class_for(keys, options.delete(:class))
|
161
172
|
error = error_for(keys, options.delete(:error))
|
@@ -170,7 +181,6 @@ module Dao
|
|
170
181
|
|
171
182
|
list = Array(from)
|
172
183
|
|
173
|
-
|
174
184
|
case list.first
|
175
185
|
when Hash, Array
|
176
186
|
nil
|
@@ -180,11 +190,21 @@ module Dao
|
|
180
190
|
list.map!{|element| [element, element]}
|
181
191
|
end
|
182
192
|
|
183
|
-
selected_value =
|
193
|
+
selected_value =
|
194
|
+
case selected
|
195
|
+
when Array
|
196
|
+
selected.first
|
197
|
+
when Hash
|
198
|
+
key = [:id, 'id', :value, 'value'].detect{|k| selected.has_key?(k)}
|
199
|
+
key ? selected[key] : selected
|
200
|
+
else
|
201
|
+
selected
|
202
|
+
end
|
184
203
|
|
185
204
|
select_(options_for(options, :name => name, :class => klass, :id => id, :data_error => error)){
|
186
205
|
list.each do |pair|
|
187
206
|
returned = block.call(pair)
|
207
|
+
|
188
208
|
case returned
|
189
209
|
when Array
|
190
210
|
value, content, selected, *ignored = returned
|
@@ -197,9 +217,11 @@ module Dao
|
|
197
217
|
content = returned
|
198
218
|
selected = nil
|
199
219
|
end
|
220
|
+
|
200
221
|
if selected.nil?
|
201
222
|
selected = value.to_s==selected_value.to_s
|
202
223
|
end
|
224
|
+
|
203
225
|
opts = {:value => value}
|
204
226
|
opts[:selected] = !!selected if selected
|
205
227
|
option_(opts){ content }
|
@@ -233,8 +255,24 @@ module Dao
|
|
233
255
|
value = Tagz.escapeHTML(data.get(keys))
|
234
256
|
end
|
235
257
|
|
258
|
+
def Form.name_for(path, *keys)
|
259
|
+
path = Path.new(path) unless path.is_a?(Path)
|
260
|
+
"#{ path }(#{ Array(keys).flatten.compact.join(',') })"
|
261
|
+
end
|
262
|
+
|
263
|
+
def Form.name_re_for(path)
|
264
|
+
path = Path.new(path) unless path.is_a?(Path)
|
265
|
+
Regexp.new(/^#{ Regexp.escape(path) }/)
|
266
|
+
end
|
267
|
+
|
268
|
+
def Form.encoded?(path, params)
|
269
|
+
name_re = Form.name_re_for(path)
|
270
|
+
params.keys.any?{|key| name_re =~ key.to_s}
|
271
|
+
end
|
272
|
+
|
273
|
+
|
236
274
|
def name_for(keys)
|
237
|
-
|
275
|
+
Form.name_for(result.path, keys)
|
238
276
|
end
|
239
277
|
|
240
278
|
def options_for(*hashes)
|
@@ -256,5 +294,11 @@ module Dao
|
|
256
294
|
def attr_for(string)
|
257
295
|
slug_for(string).gsub(/_/, '-')
|
258
296
|
end
|
297
|
+
|
298
|
+
def humanize(string)
|
299
|
+
string = string.to_s
|
300
|
+
string = string.humanize if string.respond_to?(:humanize)
|
301
|
+
string
|
302
|
+
end
|
259
303
|
end
|
260
304
|
end
|
data/lib/dao/params.rb
CHANGED
@@ -3,9 +3,11 @@ module Dao
|
|
3
3
|
include Dao::InstanceExec
|
4
4
|
|
5
5
|
class << Params
|
6
|
-
def parse(prefix, params = {})
|
6
|
+
def parse(prefix, params = {}, options = {})
|
7
7
|
prefix = prefix.to_s
|
8
|
-
params = Map.new(params)
|
8
|
+
params = Map.new(params || {})
|
9
|
+
base = Map.new(params || {})
|
10
|
+
options = Map.options(options || {})
|
9
11
|
parsed = Params.new
|
10
12
|
parsed.update(params[prefix]) if params.has_key?(prefix)
|
11
13
|
|
@@ -17,11 +19,44 @@ module Dao
|
|
17
19
|
matched, keys = re.match(key).to_a
|
18
20
|
next unless matched
|
19
21
|
next unless keys
|
20
|
-
keys = keys
|
22
|
+
keys = keys_for(keys)
|
21
23
|
parsed.set(keys => value)
|
24
|
+
base.delete(key)
|
22
25
|
end
|
23
26
|
|
24
|
-
|
27
|
+
whitelist = Set.new( [options.getopt([:include, :select, :only])].flatten.compact.map{|k| k.to_s} )
|
28
|
+
blacklist = Set.new( [options.getopt([:exclude, :reject, :except])].flatten.compact.map{|k| k.to_s} )
|
29
|
+
|
30
|
+
unless blacklist.empty?
|
31
|
+
base.keys.dup.each do |key|
|
32
|
+
base.delete(key) if blacklist.include?(key.to_s)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
unless whitelist.empty?
|
37
|
+
base.keys.dup.each do |key|
|
38
|
+
base.delete(key) unless whitelist.include?(key.to_s)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if options.getopt(:fold, default=true)
|
43
|
+
parsed_and_folded = base.merge(parsed)
|
44
|
+
else
|
45
|
+
parsed
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def keys_for(keys)
|
50
|
+
keys.strip.split(%r/\s*,\s*/).map{|key| key =~ %r/^\d+$/ ? Integer(key) : key}
|
51
|
+
end
|
52
|
+
|
53
|
+
def process(path, params, options = {})
|
54
|
+
return params if params.is_a?(Params)
|
55
|
+
|
56
|
+
parsed = Params.parse(path, params, options)
|
57
|
+
return parsed unless parsed.empty?
|
58
|
+
|
59
|
+
return Params.new(params)
|
25
60
|
end
|
26
61
|
end
|
27
62
|
|
@@ -82,52 +117,7 @@ module Dao
|
|
82
117
|
end
|
83
118
|
end
|
84
119
|
|
85
|
-
def Dao.parse(
|
86
|
-
|
87
|
-
|
88
|
-
smells_like_unparsed_rails_params = (
|
89
|
-
params.has_key?(:action) and
|
90
|
-
params.has_key?(:controller) and
|
91
|
-
params.class.name =~ /HashWithIndifferentAccess/
|
92
|
-
)
|
93
|
-
return(Params.parse(path.to_s, params)) if smells_like_unparsed_rails_params
|
94
|
-
|
95
|
-
smells_like_unparsed_params = false
|
96
|
-
unparsed_re = %r/^#{ Regexp.escape(path.to_s) }/
|
97
|
-
params.each do |key, val|
|
98
|
-
if key =~ unparsed_re
|
99
|
-
smells_like_unparsed_params = true
|
100
|
-
break
|
101
|
-
end
|
102
|
-
end
|
103
|
-
return(Params.parse(path.to_s, params)) if smells_like_unparsed_params
|
104
|
-
|
105
|
-
return Params.new(params)
|
106
|
-
end
|
107
|
-
|
108
|
-
=begin
|
109
|
-
def Dao.parse(path, params)
|
110
|
-
returned = Params.new(params)
|
111
|
-
|
112
|
-
smells_like_rails = (params.has_key?(:action) and params.has_key?(:controller) and params.class.name =~ /HashWithIndifferentAccess/)
|
113
|
-
if smells_like_rails
|
114
|
-
returned.delete(:action)
|
115
|
-
returned.delete(:controller)
|
116
|
-
returned.update(Params.parse(path, params))
|
117
|
-
return returned
|
118
|
-
end
|
119
|
-
|
120
|
-
re = %r/^#{ Regexp.escape(path) }/
|
121
|
-
smells_like_unparsed = false
|
122
|
-
params.each do |key, val|
|
123
|
-
break(smells_like_unparsed = true) if key =~ re
|
124
|
-
end
|
125
|
-
if smells_like_unparsed
|
126
|
-
returned.update(Params.parse(path, params))
|
127
|
-
return returned
|
128
|
-
end
|
129
|
-
|
130
|
-
return returned
|
120
|
+
def Dao.parse(*args, &block)
|
121
|
+
Params.process(*args, &block)
|
131
122
|
end
|
132
|
-
=end
|
133
123
|
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module Dao
|
2
|
+
class Presenter
|
3
|
+
include Tagz.globally
|
4
|
+
|
5
|
+
class << Presenter
|
6
|
+
def for(*args, &block)
|
7
|
+
new(*args, &block)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :result
|
12
|
+
attr_accessor :formats
|
13
|
+
|
14
|
+
def initialize(*args, &block)
|
15
|
+
@result = args.shift if args.first.is_a?(Result)
|
16
|
+
@formats = Map.new
|
17
|
+
end
|
18
|
+
|
19
|
+
%w( set get has has? [] ).each do |method|
|
20
|
+
module_eval <<-__, __FILE__, __LINE__
|
21
|
+
def #{ method }(*args, &block)
|
22
|
+
data.#{ method }(*args, &block)
|
23
|
+
end
|
24
|
+
__
|
25
|
+
end
|
26
|
+
|
27
|
+
def extend(*args, &block)
|
28
|
+
return super if block.nil?
|
29
|
+
singleton_class =
|
30
|
+
class << self
|
31
|
+
self
|
32
|
+
end
|
33
|
+
singleton_class.module_eval(&block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def tag(*args, &block)
|
37
|
+
options = Dao.options_for!(args)
|
38
|
+
args.push(:div) if args.empty?
|
39
|
+
tagname = args.shift
|
40
|
+
keys = args
|
41
|
+
|
42
|
+
tag_method = "#{ tagname }_"
|
43
|
+
|
44
|
+
id = options.delete(:id) || id_for(keys)
|
45
|
+
klass = class_for(keys, options.delete(:class))
|
46
|
+
error = error_for(keys, options.delete(:error))
|
47
|
+
|
48
|
+
tag_options =
|
49
|
+
options_for(options, :id => id, :class => klass, :data_error => error)
|
50
|
+
|
51
|
+
value = value_for(keys)
|
52
|
+
tag_value = instance_exec(value, &format_for(keys))
|
53
|
+
|
54
|
+
send(tag_method, tag_options){ tag_value }
|
55
|
+
end
|
56
|
+
|
57
|
+
include InstanceExec
|
58
|
+
|
59
|
+
DefaultFormat = lambda{|value| value}
|
60
|
+
|
61
|
+
def format_for(keys)
|
62
|
+
formats.get(keys) || DefaultFormat
|
63
|
+
end
|
64
|
+
|
65
|
+
def format(list_of_keys, &block)
|
66
|
+
Array(list_of_keys).each do |keys|
|
67
|
+
formats.set(keys, block)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def data
|
72
|
+
result.data
|
73
|
+
end
|
74
|
+
|
75
|
+
def errors
|
76
|
+
result.errors
|
77
|
+
end
|
78
|
+
|
79
|
+
def ==(other)
|
80
|
+
result == other.result
|
81
|
+
end
|
82
|
+
|
83
|
+
def id_for(keys)
|
84
|
+
id = [result.path, keys.join('-')].compact.join('_')
|
85
|
+
slug_for(id)
|
86
|
+
end
|
87
|
+
|
88
|
+
def class_for(keys, klass = nil)
|
89
|
+
klass =
|
90
|
+
if result.errors.on?(keys)
|
91
|
+
[klass, 'dao', 'errors'].compact.join(' ')
|
92
|
+
else
|
93
|
+
[klass, 'dao'].compact.join(' ')
|
94
|
+
end
|
95
|
+
klass
|
96
|
+
end
|
97
|
+
|
98
|
+
def error_for(keys, klass = nil)
|
99
|
+
if result.errors.on?(keys)
|
100
|
+
result.errors.get(keys)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def value_for(keys)
|
105
|
+
return nil unless data.has?(keys)
|
106
|
+
value = Tagz.escapeHTML(data.get(keys))
|
107
|
+
end
|
108
|
+
|
109
|
+
def options_for(*hashes)
|
110
|
+
map = Map.new
|
111
|
+
hashes.flatten.each do |h|
|
112
|
+
h.each{|k,v| map[attr_for(k)] = v unless v.nil?}
|
113
|
+
end
|
114
|
+
map
|
115
|
+
end
|
116
|
+
|
117
|
+
def slug_for(string)
|
118
|
+
string = string.to_s
|
119
|
+
words = string.to_s.scan(%r/\w+/)
|
120
|
+
words.map!{|word| word.gsub(%r/[^0-9a-zA-Z_:-]/, '')}
|
121
|
+
words.delete_if{|word| word.nil? or word.strip.empty?}
|
122
|
+
words.join('-').downcase.sub(/_+$/, '')
|
123
|
+
end
|
124
|
+
|
125
|
+
def attr_for(string)
|
126
|
+
slug_for(string).gsub(/_/, '-')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/dao/rails.rb
CHANGED
@@ -7,12 +7,60 @@ if defined?(Rails)
|
|
7
7
|
### ref: https://gist.github.com/af7e572c2dc973add221
|
8
8
|
|
9
9
|
paths.path = ROOT_DIR
|
10
|
+
|
10
11
|
### config.autoload_paths << APP_DIR
|
11
12
|
### $LOAD_PATH.push(File.join(Rails.root.to_s, 'app'))
|
12
|
-
|
13
13
|
#config.after_initialize do
|
14
14
|
#unloadable(Dao)
|
15
15
|
#end
|
16
|
+
|
17
|
+
|
18
|
+
# yes yes, this should probably be somewhere else...
|
19
|
+
#
|
20
|
+
config.after_initialize do
|
21
|
+
|
22
|
+
ActionController::Base.module_eval do
|
23
|
+
|
24
|
+
# you will likely want to override this!
|
25
|
+
#
|
26
|
+
def current_api
|
27
|
+
@api ||= (
|
28
|
+
api = Api.new
|
29
|
+
%w( real_user effective_user current_user ).each do |attr|
|
30
|
+
getter = "#{ attr }"
|
31
|
+
setter = "#{ attr }="
|
32
|
+
if respond_to?(getter) and api.respond_to?(setter)
|
33
|
+
api.send(setter, send(getter))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
api
|
37
|
+
)
|
38
|
+
end
|
39
|
+
helper_method(:current_api)
|
40
|
+
alias_method(:api, :current_api)
|
41
|
+
helper_method(:api)
|
42
|
+
|
43
|
+
# setup sane rescuing from dao errors with crap statuses
|
44
|
+
#
|
45
|
+
rescue_from(Dao::Error::Result) do |error|
|
46
|
+
result = error.result
|
47
|
+
basename = "#{ result.status.code }.html"
|
48
|
+
error_page = File.join(Rails.root, 'public', basename)
|
49
|
+
|
50
|
+
if test(?e, error_page)
|
51
|
+
file = File.expand_path(error_page)
|
52
|
+
status = result.status.code
|
53
|
+
render(:file => file, :status => status, :layout => false)
|
54
|
+
else
|
55
|
+
text = result.status.to_s
|
56
|
+
status = result.status.code
|
57
|
+
render(:text => text, :status => status, :layout => false)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
16
64
|
end
|
17
65
|
end
|
18
66
|
end
|
@@ -12,8 +12,7 @@ class DaoGenerator < Rails::Generators::NamedBase
|
|
12
12
|
|
13
13
|
copy_file("dao.css", "public/stylesheets/dao.css")
|
14
14
|
|
15
|
-
route("match 'api/*path' => 'api#
|
16
|
-
route("match 'api' => 'api#index', :as => 'api_index'")
|
15
|
+
route("match 'api(/*path)' => 'api#index', :as => 'api'")
|
17
16
|
|
18
17
|
gem("yajl-ruby")
|
19
18
|
|