dao 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/dao/api.rb CHANGED
@@ -3,7 +3,7 @@ module Dao
3
3
  Dao.load 'api/initializers.rb'
4
4
  Dao.load 'api/modes.rb'
5
5
  Dao.load 'api/context.rb'
6
- Dao.load 'api/endpoints.rb'
6
+ Dao.load 'api/interfaces.rb'
7
7
  Dao.load 'api/dsl.rb'
8
8
  end
9
9
  end
@@ -1,24 +1,24 @@
1
1
  module Dao
2
2
  class Context
3
- Attrs = %w( api endpoint params result method args )
3
+ Attrs = %w( api interface params result method args )
4
4
  Attrs.each{|attr| attr_accessor(attr)}
5
5
 
6
6
  def initialize(*args, &block)
7
7
  options = Dao.options_for!(args)
8
8
 
9
9
  api = options[:api]
10
- endpoint = options[:endpoint]
10
+ interface = options[:interface]
11
11
  params = options[:params]
12
12
 
13
- params = Params.for(:api => api, :endpoint => endpoint, :params => params)
14
- result = Result.new(:api => api, :endpoint => endpoint, :params => params)
13
+ params = Params.for(:api => api, :interface => interface, :params => params)
14
+ result = Result.new(:api => api, :interface => interface, :params => params)
15
15
  params.result = result
16
16
 
17
- method = endpoint.method.bind(api)
17
+ method = interface.method.bind(api)
18
18
  args = [params, result].slice(0, method.arity)
19
19
 
20
20
  self.api = api
21
- self.endpoint = endpoint
21
+ self.interface = interface
22
22
  self.params = params
23
23
  self.result = result
24
24
  self.method = method
data/lib/dao/api/dsl.rb CHANGED
@@ -16,10 +16,10 @@ module Dao
16
16
  end
17
17
 
18
18
  def no_docs_left_on_stack!
19
- raise "no endpoint for #{ docs.inspect }" unless docs.empty?
19
+ raise "no interface for #{ docs.inspect }" unless docs.empty?
20
20
  end
21
21
 
22
- %w( endpoint doc docs description desc ).each do |method|
22
+ %w( interface doc docs description desc ).each do |method|
23
23
  module_eval <<-__, __FILE__, __LINE__ - 1
24
24
 
25
25
  def #{ method }(*args, &block)
@@ -0,0 +1,232 @@
1
+ module Dao
2
+ class Api
3
+ class << Api
4
+ def interfaces
5
+ @interfaces ||= Map.new
6
+ end
7
+
8
+ def interface(path, &block)
9
+ api = self
10
+ path = Path.new(path)
11
+
12
+ method =
13
+ module_eval{
14
+ define_method(path + '/interface', &block)
15
+ instance_method(path + '/interface')
16
+ }
17
+
18
+
19
+ interface = Interface.new(
20
+ 'api' => api,
21
+ 'path' => path,
22
+ 'method' => method,
23
+ 'doc' => docs.pop
24
+ )
25
+
26
+ interfaces[path] = interface
27
+ end
28
+
29
+ def description(string)
30
+ doc(:description => Dao.unindent(string))
31
+ end
32
+ alias_method('desc', 'description')
33
+
34
+ def doc(*args)
35
+ docs.push(Map[:description, nil]) if docs.empty?
36
+ doc = docs.last
37
+ options = Dao.options_for!(args)
38
+ if options.empty?
39
+ options[:description] = args.join(' ')
40
+ end
41
+ doc.update(options)
42
+ doc
43
+ end
44
+
45
+ def docs
46
+ @docs ||= []
47
+ end
48
+
49
+ def index
50
+ index = Map.new
51
+ interfaces.each do |path, interface|
52
+ index[path] = interface.doc || {'description' => path}
53
+ end
54
+ index
55
+ end
56
+ end
57
+
58
+ def call(path = '/index', params = {})
59
+ api = self
60
+ path = Path.new(path)
61
+ interface = interfaces[path]
62
+ raise(NameError, "NO SUCH INTERFACE: #{ path }") unless interface
63
+
64
+ params = Dao.parse(path, params)
65
+
66
+ context = Context.new(
67
+ :api => api,
68
+ :interface => interface,
69
+ :params => params
70
+ )
71
+
72
+ callstack(context) do
73
+ catching(:result){ context.call() }
74
+ end
75
+
76
+ context.result
77
+ end
78
+
79
+ def index
80
+ self.class.index
81
+ end
82
+
83
+ def interfaces
84
+ self.class.interfaces
85
+ end
86
+
87
+ def context
88
+ callstack.last || raise('no context!')
89
+ end
90
+
91
+ def result
92
+ context.result
93
+ end
94
+
95
+ def params
96
+ result.params
97
+ end
98
+
99
+ def errors
100
+ result.errors
101
+ end
102
+
103
+ def apply(hash = {})
104
+ data.apply(hash)
105
+ end
106
+
107
+ def update(hash = {})
108
+ data.update(hash)
109
+ end
110
+
111
+ def default(*args)
112
+ hash = Map.options_for!(args)
113
+ if hash.empty?
114
+ value = args.pop
115
+ key = args
116
+ hash = {key => value}
117
+ end
118
+ data.apply(hash)
119
+ end
120
+
121
+ def status(*args, &block)
122
+ result.status(*args, &block)
123
+ end
124
+
125
+ def data(*args)
126
+ if args.empty?
127
+ result.data
128
+ else
129
+ result.data.replace(*args)
130
+ end
131
+ end
132
+
133
+ def data!(*args)
134
+ result.data.replace(*args)
135
+ valid!
136
+ end
137
+
138
+ def update(*args, &block)
139
+ data.update(*args, &block)
140
+ end
141
+
142
+ def replace(*args, &block)
143
+ data.replace(*args, &block)
144
+ end
145
+
146
+ def validations
147
+ result.validations
148
+ end
149
+
150
+ def validates(*args, &block)
151
+ result.validates(*args, &block)
152
+ end
153
+
154
+ def validate
155
+ result.validate
156
+ end
157
+
158
+ def valid?
159
+ result.valid?
160
+ end
161
+
162
+ def validate!
163
+ result.validate!
164
+ end
165
+
166
+ def valid!
167
+ result.valid!
168
+ end
169
+
170
+ include Validations::Common
171
+
172
+ def return!(*value)
173
+ throw(:result, *value)
174
+ end
175
+
176
+ =begin
177
+ def set(*args, &block)
178
+ result.data.set(*args, &block)
179
+ end
180
+
181
+ def get(*args, &block)
182
+ params.data.get(*args, &block)
183
+ end
184
+ =end
185
+
186
+ def callstack(context = nil, &block)
187
+ @callstack ||= []
188
+
189
+ if block and context
190
+ begin
191
+ @callstack.push(context)
192
+ return block.call()
193
+ ensure
194
+ @callstack.pop
195
+ end
196
+ else
197
+ @callstack
198
+ end
199
+ end
200
+
201
+ def catching(label = :result, &block)
202
+ @catching ||= []
203
+
204
+ if block
205
+ begin
206
+ @catching.push(label)
207
+ catch(label, &block)
208
+ ensure
209
+ @catching.pop
210
+ end
211
+ else
212
+ @catching.last
213
+ end
214
+ end
215
+
216
+ def catching_results(&block)
217
+ catching(:result, &block)
218
+ end
219
+
220
+ def catching?
221
+ catching
222
+ end
223
+
224
+ def catching_results?
225
+ catching == :result
226
+ end
227
+
228
+ def respond_to?(*args)
229
+ super(*args) || super(Path.absolute_path_for(*args))
230
+ end
231
+ end
232
+ end
data/lib/dao/api/modes.rb CHANGED
@@ -19,7 +19,14 @@ module Dao
19
19
 
20
20
  def #{ mode }(*args, &block)
21
21
  if args.empty?
22
- mode(#{ mode.inspect }, &block)
22
+ if catching_results?
23
+ if self.mode == #{ mode.inspect }
24
+ mode(#{ mode.inspect }, &block)
25
+ return!
26
+ end
27
+ else
28
+ mode(#{ mode.inspect }, &block)
29
+ end
23
30
  else
24
31
  mode(#{ mode.inspect }) do
25
32
  call(*args, &block)
@@ -68,11 +75,7 @@ module Dao
68
75
  if block.nil?
69
76
  condition
70
77
  else
71
- if condition
72
- result = block.call
73
- throw(:result, result) if catching_the_result?
74
- result
75
- end
78
+ send(mode, &block) if condition
76
79
  end
77
80
  end
78
81
  end
data/lib/dao/data.rb CHANGED
@@ -2,6 +2,13 @@ module Dao
2
2
  class Data < ::Map
3
3
  add_conversion_method!(:to_dao)
4
4
  add_conversion_method!(:as_dao)
5
+
6
+ def update(*args, &block)
7
+ if args.size==1 and args.first.respond_to?(:to_dao)
8
+ update(args.first.to_dao)
9
+ end
10
+ super
11
+ end
5
12
  end
6
13
  end
7
14
 
data/lib/dao/errors.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  module Dao
2
2
  class Errors < ::Map
3
+ include Tagz.globally
4
+ class << Errors
5
+ include Tagz.globally
6
+ end
7
+
3
8
  Global = '*' unless defined?(Global)
4
- Separator = ':' unless defined?(Separator)
9
+ Separator = '' unless defined?(Separator)
5
10
 
6
11
  class Message < ::String
7
12
  attr_accessor :sticky
@@ -129,7 +134,7 @@ module Dao
129
134
  end
130
135
 
131
136
  def invalid?(*keys)
132
- !get(keys).nil?
137
+ has?(keys) and !get(keys).nil?
133
138
  end
134
139
 
135
140
  alias_method 'on?', 'invalid?'
@@ -146,6 +151,7 @@ module Dao
146
151
  alias_method 'length', 'size'
147
152
 
148
153
  def full_messages
154
+ global_messages = []
149
155
  full_messages = []
150
156
 
151
157
  depth_first_each do |keys, value|
@@ -153,21 +159,14 @@ module Dao
153
159
  key = keys.join('.')
154
160
  value = value.to_s
155
161
  next if value.strip.empty?
156
- full_messages.push([key, value])
157
- end
158
-
159
- full_messages.sort! do |a,b|
160
- a, b = a.first, b.first
161
- if a == Global
162
- b == Global ? 0 : -1
163
- elsif b == Global
164
- a == Global ? 0 : 1
162
+ if key == Global
163
+ global_messages.push([key, value])
165
164
  else
166
- a <=> b
165
+ full_messages.push([key, value])
167
166
  end
168
167
  end
169
168
 
170
- full_messages
169
+ global_messages + full_messages
171
170
  end
172
171
 
173
172
  def each_message
@@ -208,27 +207,25 @@ module Dao
208
207
  options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
209
208
  errors = [error, *args].flatten.compact
210
209
 
211
- at_least_one = false
210
+ at_least_one_error = false
212
211
  css_class = options[:class] || 'dao errors'
213
212
 
214
- html = []
215
-
216
- html.push("<table class='#{ css_class }'>")
217
- html.push("<caption>Sorry, there were some errors.</caption>")
218
- errors.each do |e|
219
- e.full_messages.each do |key, value|
220
- at_least_one = true
221
- key = key.to_s
222
- html.push("<tr class='field'>")
223
- html.push("<td class='field'>#{ key }</td>")
224
- html.push("<td class='separator'>#{ Separator }</td>")
225
- html.push("<td class='message'>#{ value }</td>")
226
- html.push("</tr>")
213
+ to_html =
214
+ table_(:class => css_class){
215
+ caption_{ "We're so sorry, but can you please fix the following errors?" }
216
+ errors.each do |e|
217
+ e.full_messages.each do |key, message|
218
+ at_least_one_error = true
219
+ tr_{
220
+ td_(:class => :key){ key }
221
+ td_(:class => :separator){ Separator }
222
+ td_(:class => :message){ message }
223
+ }
224
+ end
227
225
  end
228
- end
229
- html.push("</table>")
226
+ }
230
227
 
231
- at_least_one ? html.join("\n") : ''
228
+ at_least_one_error ? to_html : ''
232
229
  end
233
230
 
234
231
  def to_s(*args, &block)
data/lib/dao/form.rb CHANGED
@@ -24,18 +24,18 @@ module Dao
24
24
  super
25
25
  end
26
26
 
27
- def params
28
- result.params
29
- end
30
-
31
- def ==(other)
32
- params.object_id == other.params.object_id
27
+ def data
28
+ result.data
33
29
  end
34
30
 
35
31
  def errors
36
32
  result.errors
37
33
  end
38
34
 
35
+ def ==(other)
36
+ result == other.result
37
+ end
38
+
39
39
  def form(*args, &block)
40
40
  options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
41
41
  keys = args.flatten
@@ -87,9 +87,9 @@ module Dao
87
87
 
88
88
  value =
89
89
  if block.nil? and !options.has_key?(:value)
90
- value_for(params, keys)
90
+ value_for(data, keys)
91
91
  else
92
- block ? block.call(params.get(keys)) : options.delete(:value)
92
+ block ? block.call(data.get(keys)) : options.delete(:value)
93
93
  end
94
94
 
95
95
  input_(options_for(options, :type => type, :name => name, :value => value, :class => klass, :id => id, :data_error => error)){}
@@ -115,9 +115,9 @@ module Dao
115
115
 
116
116
  value =
117
117
  if block.nil? and !options.has_key?(:value)
118
- value_for(params, keys)
118
+ value_for(data, keys)
119
119
  else
120
- block ? block.call(params.get(keys)) : options.delete(:value)
120
+ block ? block.call(data.get(keys)) : options.delete(:value)
121
121
  end
122
122
 
123
123
  button_(options_for(options, :type => type, :name => name, :value => value, :class => klass, :id => id, :data_error => error)){}
@@ -141,12 +141,12 @@ module Dao
141
141
 
142
142
  value =
143
143
  if block.nil? and !options.has_key?(:value)
144
- value_for(params, keys)
144
+ value_for(data, keys)
145
145
  else
146
- block ? block.call(params.get(keys)) : options.delete(:value)
146
+ block ? block.call(data.get(keys)) : options.delete(:value)
147
147
  end
148
148
 
149
- textarea_(options_for(options, :name => name, :class => klass, :id => id, :data_error => error)){ value }
149
+ textarea_(options_for(options, :name => name, :class => klass, :id => id, :data_error => error)){ value.to_s }
150
150
  end
151
151
 
152
152
  def select(*args, &block)
@@ -154,27 +154,51 @@ module Dao
154
154
  keys = args.flatten
155
155
 
156
156
  name = options.delete(:name) || name_for(keys)
157
- from = options.delete(:from) || options.delete(:select) || options.delete(:all) || options.delete(:list)
157
+ from = options.delete(:from) || options.delete(:options)
158
158
 
159
159
  id = options.delete(:id) || id_for(keys)
160
160
  klass = class_for(keys, options.delete(:class))
161
161
  error = error_for(keys, options.delete(:error))
162
162
 
163
+ block ||= lambda{|pair| pair = Array(pair).flatten.compact; [pair.first, pair.last, selected=nil]}
164
+
165
+ if from.nil?
166
+ key = keys.map{|key| "#{ key }"}
167
+ key.last << "_options"
168
+ from = data.get(*key) if data.has?(*key)
169
+ end
170
+
171
+ list = Array(from)
172
+
173
+
174
+ case list.first
175
+ when Hash, Array
176
+ nil
177
+ else
178
+ list.flatten!
179
+ list.compact!
180
+ list.map!{|element| [element, element]}
181
+ end
182
+
183
+ selected_value = value_for(data, keys)
184
+
163
185
  select_(options_for(options, :name => name, :class => klass, :id => id, :data_error => error)){
164
- pairs = Array(params[from]).flatten
165
- pairs.each do |pair|
166
- result = block.call(pair)
167
- case result
186
+ list.each do |pair|
187
+ returned = block.call(pair)
188
+ case returned
168
189
  when Array
169
- value, content, selected, *ignored = result
190
+ value, content, selected, *ignored = returned
170
191
  when Hash
171
- value = result[:value]
172
- content = result[:content] || value
173
- selected = result[:selected]
192
+ value = returned[:value]
193
+ content = returned[:content] || value
194
+ selected = returned[:selected]
174
195
  else
175
- value = result
176
- content = result
177
- selected = false
196
+ value = returned
197
+ content = returned
198
+ selected = nil
199
+ end
200
+ if selected.nil?
201
+ selected = value.to_s==selected_value.to_s
178
202
  end
179
203
  opts = {:value => value}
180
204
  opts[:selected] = !!selected if selected
@@ -204,9 +228,9 @@ module Dao
204
228
  end
205
229
  end
206
230
 
207
- def value_for(params, keys)
208
- return nil unless params.has?(keys)
209
- value = Tagz.escapeHTML(params.get(keys))
231
+ def value_for(data, keys)
232
+ return nil unless data.has?(keys)
233
+ value = Tagz.escapeHTML(data.get(keys))
210
234
  end
211
235
 
212
236
  def name_for(keys)