dao 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)