dao 3.3.0 → 4.2.1

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.
Files changed (60) hide show
  1. data/README +7 -0
  2. data/Rakefile +36 -17
  3. data/b.rb +38 -0
  4. data/dao.gemspec +41 -13
  5. data/lib/dao.rb +44 -13
  6. data/lib/dao/api.rb +1 -1
  7. data/lib/dao/api/context.rb +35 -45
  8. data/lib/dao/api/endpoints.rb +225 -91
  9. data/lib/dao/conducer.rb +437 -0
  10. data/lib/dao/conducer/attributes.rb +21 -0
  11. data/lib/dao/conducer/crud.rb +70 -0
  12. data/lib/dao/current.rb +66 -0
  13. data/lib/dao/db.rb +44 -5
  14. data/lib/dao/endpoint.rb +13 -1
  15. data/lib/dao/errors.rb +74 -59
  16. data/lib/dao/exceptions.rb +1 -2
  17. data/lib/dao/extractor.rb +68 -0
  18. data/lib/dao/form.rb +139 -46
  19. data/lib/dao/image_cache.rb +193 -0
  20. data/lib/dao/instance_exec.rb +1 -1
  21. data/lib/dao/name.rb +7 -0
  22. data/lib/dao/params.rb +16 -66
  23. data/lib/dao/rack.rb +3 -0
  24. data/lib/dao/rack/middleware.rb +5 -0
  25. data/lib/dao/rack/middleware/params_parser.rb +24 -0
  26. data/lib/dao/rails.rb +22 -5
  27. data/lib/dao/rails/lib/generators/dao/USAGE +2 -6
  28. data/lib/dao/rails/lib/generators/dao/dao_generator.rb +52 -7
  29. data/lib/dao/rails/lib/generators/dao/templates/api.rb +23 -7
  30. data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +24 -7
  31. data/lib/dao/rails/lib/generators/dao/templates/conducer.rb +64 -0
  32. data/lib/dao/rails/lib/generators/dao/templates/conducer_controller.rb +79 -0
  33. data/lib/dao/rails/lib/generators/dao/templates/dao.js +13 -6
  34. data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +75 -11
  35. data/lib/dao/result.rb +1 -26
  36. data/lib/dao/slug.rb +37 -8
  37. data/lib/dao/status.rb +4 -0
  38. data/lib/dao/support.rb +155 -0
  39. data/lib/dao/validations.rb +48 -157
  40. data/lib/dao/validations/callback.rb +30 -0
  41. data/lib/dao/validations/common.rb +322 -320
  42. data/lib/dao/validations/validator.rb +219 -0
  43. data/test/active_model_conducer_lint_test.rb +19 -0
  44. data/test/api_test.rb +261 -0
  45. data/test/conducer_test.rb +205 -0
  46. data/test/db.yml +9 -0
  47. data/test/form_test.rb +42 -0
  48. data/test/support_test.rb +52 -0
  49. data/test/testing.rb +145 -24
  50. data/test/validations_test.rb +156 -0
  51. metadata +138 -21
  52. data/TODO +0 -33
  53. data/a.rb +0 -80
  54. data/db/dao.yml +0 -5
  55. data/lib/dao/api/interfaces.rb +0 -306
  56. data/lib/dao/interface.rb +0 -28
  57. data/lib/dao/presenter.rb +0 -129
  58. data/lib/dao/rails/lib/generators/dao/api_generator.rb +0 -3
  59. data/lib/dao/validations/base.rb +0 -68
  60. data/test/dao_test.rb +0 -506
@@ -0,0 +1,21 @@
1
+ module Dao
2
+ class Conducer
3
+ class Attributes < ::Map
4
+ ### Attributes.dot_keys! if Attributes.respond_to?(:dot_keys!)
5
+
6
+ class << Attributes
7
+ def for(*args, &block)
8
+ new(*args, &block)
9
+ end
10
+ end
11
+
12
+ attr_accessor :conducer
13
+
14
+ def initialize(*args, &block)
15
+ conducers, args = args.partition{|arg| arg.is_a?(Conducer)}
16
+ @conducer = conducers.shift
17
+ super(*args, &block)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,70 @@
1
+ module Dao
2
+ ## CRUD support
3
+ #
4
+ class Conducer
5
+ module CRUD
6
+ Code = proc do
7
+ class << self
8
+ def db
9
+ Db.instance
10
+ end
11
+
12
+ def collection
13
+ db[collection_name]
14
+ end
15
+
16
+ def all(*args)
17
+ hashes = collection.all()
18
+ hashes.map{|hash| new(hash)}
19
+ end
20
+
21
+ def find(id)
22
+ hash = collection.find(id)
23
+ new(hash) if hash
24
+ end
25
+ end
26
+
27
+ def save
28
+ run_callbacks :save do
29
+ return(false) unless valid?
30
+ id = self.class.collection.save(@attributes)
31
+ @attributes.set(:id => id)
32
+ true
33
+ end
34
+ ensure
35
+ @new_record = false
36
+ end
37
+
38
+ def destroy
39
+ id = self.id
40
+ if id
41
+ self.class.collection.destroy(id)
42
+ @attributes.rm(:id)
43
+ end
44
+ id
45
+ ensure
46
+ @destroyed = true
47
+ end
48
+ end
49
+
50
+ def CRUD.included(other)
51
+ super
52
+ ensure
53
+ other.module_eval(&Code)
54
+ end
55
+ end
56
+ end
57
+
58
+ ## dsl for auto-crud
59
+ #
60
+ class Conducer
61
+ class << self
62
+ def crud
63
+ include(Conducer::CRUD)
64
+ end
65
+ alias_method('crud!', 'crud')
66
+ alias_method('autocrud!', 'crud')
67
+ end
68
+ end
69
+ #Conducer::send(:include, Conducer::CRUD)
70
+ end
@@ -0,0 +1,66 @@
1
+ # FIXME - the redundancy in this file fucking kilz me... fix it.
2
+ #
3
+ module Dao::Current
4
+ Methods = proc do
5
+ end
6
+
7
+ ClassMethods = proc do
8
+ def current_controller
9
+ @current_controller ||= (
10
+ if defined?(@controller)
11
+ @controller
12
+ else
13
+ Dao.current_controller || Dao.mock_controller
14
+ end
15
+ )
16
+ end
17
+
18
+ %w( request response session ).each do |attr|
19
+ instance_eval <<-__, __FILE__, __LINE__
20
+ def current_#{ attr }
21
+ @current_#{ attr } ||= current_controller.instance_eval{ #{ attr } }
22
+ end
23
+ __
24
+ end
25
+
26
+ %w( current_user effective_user real_user ).each do |attr|
27
+ instance_eval <<-__, __FILE__, __LINE__
28
+ def #{ attr }
29
+ @#{ attr } ||= current_controller.instance_eval{ #{ attr } }
30
+ end
31
+ def #{ attr }=(value)
32
+ @#{ attr } = value
33
+ end
34
+ __
35
+ end
36
+ end
37
+
38
+ InstanceMethods = proc do
39
+ def current_controller
40
+ @current_controller ||= (
41
+ if defined?(@controller)
42
+ @controller
43
+ else
44
+ self.class.current_controller
45
+ end
46
+ )
47
+ end
48
+
49
+ %w( current_request current_response current_session current_user effective_user real_user ).each do |attr|
50
+ module_eval <<-__, __FILE__, __LINE__
51
+ def #{ attr }
52
+ @#{ attr } ||= self.class.send('#{ attr }')
53
+ end
54
+ def #{ attr }=(value)
55
+ @#{ attr } = value
56
+ end
57
+ __
58
+ end
59
+ end
60
+
61
+ def self.included(other)
62
+ other.send(:instance_eval, &ClassMethods)
63
+ other.send(:class_eval, &InstanceMethods)
64
+ super
65
+ end
66
+ end
data/lib/dao/db.rb CHANGED
@@ -7,11 +7,23 @@ module Dao
7
7
  attr_accessor :path
8
8
 
9
9
  def initialize(*args)
10
- options = Dao.options_for!(args)
11
- @path = (args.shift || options[:path] || './db/dao.yml').to_s
10
+ options = args.extract_options!.to_options!
11
+ @path = ( args.shift || options[:path] || Db.default_path ).to_s
12
12
  FileUtils.mkdir_p(File.dirname(@path)) rescue nil
13
13
  end
14
14
 
15
+ def rm_f
16
+ FileUtils.rm_f(@path) rescue nil
17
+ end
18
+
19
+ def rm_rf
20
+ FileUtils.rm_rf(@path) rescue nil
21
+ end
22
+
23
+ def truncate
24
+ rm_f
25
+ end
26
+
15
27
  def db
16
28
  self
17
29
  end
@@ -53,7 +65,9 @@ module Dao
53
65
 
54
66
  def delete(id)
55
67
  @db.delete(@name, id)
68
+ id
56
69
  end
70
+ alias_method('destroy', 'delete')
57
71
 
58
72
  def to_hash
59
73
  transaction{|y| y[@name]}
@@ -73,17 +87,25 @@ module Dao
73
87
  end
74
88
  alias_method('[]', 'collection')
75
89
 
90
+ def method_missing(method, *args, &block)
91
+ if args.empty? and block.nil?
92
+ return self.collection(method)
93
+ end
94
+ super
95
+ end
96
+
76
97
  def transaction(*args, &block)
77
98
  ystore.transaction(*args, &block)
78
99
  end
79
100
 
80
- def save(collection, data = {})
101
+ def save(collection, data)
81
102
  data = data_for(data)
82
103
  ystore.transaction do |y|
83
104
  collection = (y[collection.to_s] ||= {})
84
105
  id = next_id_for(collection, data)
85
106
  collection[id] = data
86
107
  record = collection[id]
108
+ id
87
109
  end
88
110
  end
89
111
 
@@ -133,6 +155,7 @@ module Dao
133
155
  end
134
156
  end
135
157
  end
158
+ alias_method('destroy', 'delete')
136
159
 
137
160
  def next_id_for(collection, data)
138
161
  data = data_for(data)
@@ -167,11 +190,11 @@ module Dao
167
190
  attr_writer :instance
168
191
 
169
192
  def default_root()
170
- defined?(Rails.root) ? File.join(Rails.root.to_s, 'db') : './db'
193
+ defined?(Rails.root) && Rails.root ? File.join(Rails.root.to_s, 'db') : './db'
171
194
  end
172
195
 
173
196
  def default_path()
174
- File.join(default_root, 'dao.yml')
197
+ File.join(default_root, 'db.yml')
175
198
  end
176
199
 
177
200
  def method_missing(method, *args, &block)
@@ -186,6 +209,22 @@ module Dao
186
209
  def root
187
210
  @root ||= default_root
188
211
  end
212
+
213
+ def tmp(&block)
214
+ require 'tempfile' unless defined?(Tempfile)
215
+ tempfile = Tempfile.new("#{ Process.pid }-#{ Process.ppid }-#{ Time.now.to_f }-#{ rand }")
216
+ path = tempfile.path
217
+ db = new(:path => path)
218
+ if block
219
+ begin
220
+ block.call(db)
221
+ ensure
222
+ db.rm_rf
223
+ end
224
+ else
225
+ db
226
+ end
227
+ end
189
228
  end
190
229
  end
191
230
  end
data/lib/dao/endpoint.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Dao
2
2
  class Endpoint
3
- Attrs = %w( api path method doc )
3
+ Attrs = %w( api path route block doc )
4
4
  Attrs.each{|attr| attr_accessor(attr)}
5
5
 
6
6
  def initialize(options = {})
@@ -12,5 +12,17 @@ module Dao
12
12
  send("#{ key }=", val)
13
13
  end
14
14
  end
15
+
16
+ def arity
17
+ block.arity
18
+ end
19
+
20
+ def call(*args)
21
+ block.call(*args)
22
+ end
23
+
24
+ def to_proc
25
+ block
26
+ end
15
27
  end
16
28
  end
data/lib/dao/errors.rb CHANGED
@@ -6,22 +6,28 @@ module Dao
6
6
 
7
7
  class << Errors
8
8
  include Tagz.globally
9
+
10
+ def for(*args, &block)
11
+ if args.size == 1 and args.first.is_a?(Errors)
12
+ return args.first
13
+ end
14
+ new(*args, &block)
15
+ end
9
16
  end
10
17
 
11
18
  # you can tweak these if you want
12
19
  #
13
20
  Global = '*' unless defined?(Global)
14
- #Separator = '⇒' unless defined?(Separator)
15
- Separator = "\342\207\222" unless defined?(Separator) ### this is an "Open-outlined rightward arrow" - http://en.wikipedia.org/wiki/List_of_Unicode_characters#Supplemental_arrows-A
16
-
21
+ #Separator = "\342\207\222" unless defined?(Separator) ### this is an "Open-outlined rightward arrow"
22
+ Separator = ":" unless defined?(Separator)
17
23
 
18
- # string message support class - knows when it's sticky...
24
+ # messages know when they're sticky
19
25
  #
20
26
  class Message < ::String
21
27
  attr_accessor :sticky
22
28
 
23
29
  def initialize(*args)
24
- options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
30
+ options = Map.options_for!(args)
25
31
  replace(args.join(' '))
26
32
  @sticky = options[:sticky]
27
33
  end
@@ -42,16 +48,35 @@ module Dao
42
48
  def global_key
43
49
  [Global]
44
50
  end
45
-
46
- def for(*args, &block)
47
- new(*args, &block)
48
- end
49
51
  end
50
52
 
51
53
  # instance methods
52
54
  #
55
+ attr_accessor :object
56
+
57
+ def initialize(*args)
58
+ @object = args.shift
59
+ end
60
+
61
+ def errors
62
+ self
63
+ end
64
+
65
+ def [](key)
66
+ self[key] = Array.new unless has_key?(key)
67
+ super
68
+ end
69
+
70
+ def size
71
+ size = 0
72
+ depth_first_each{|key, val| size += Array(val).size}
73
+ size
74
+ end
75
+ alias_method('count', 'size')
76
+ alias_method('length', 'size')
77
+
53
78
  def add(*args)
54
- options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
79
+ options = Map.options_for!(args)
55
80
  sticky = options[:sticky]
56
81
  clear = options[:clear]
57
82
 
@@ -85,7 +110,7 @@ module Dao
85
110
 
86
111
  errors.each do |keys, message|
87
112
  list = get(keys)
88
- unless get(keys)
113
+ unless has?(keys)
89
114
  set(keys => [])
90
115
  list = get(keys)
91
116
  end
@@ -96,42 +121,20 @@ module Dao
96
121
 
97
122
  result
98
123
  end
124
+
99
125
  alias_method('add_to_base', 'add')
100
126
 
101
127
  def add!(*args)
102
- options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
128
+ options = Map.new(args.last.is_a?(Hash) ? args.last : {})
103
129
  options[:sticky] = true
104
130
  args.push(options)
105
131
  add(*args)
106
132
  end
107
- alias_method('add_to_base!', 'add!')
108
133
 
109
- def clone
110
- clone = Errors.new
111
- depth_first_each do |keys, message|
112
- args = [*keys]
113
- args.push(message)
114
- clone.add(*args)
115
- end
116
- clone
117
- end
118
-
119
- def update(other, options = {})
120
- options = Dao.map_for(options)
121
- prefix = Array(options[:prefix]).flatten.compact
134
+ alias_method('add_to_base!', 'add!')
122
135
 
123
- other.each do |key, val|
124
- key = key.to_s
125
- if key == 'base' or key == Global
126
- add!(val)
127
- else
128
- key = prefix + [key] unless prefix.empty?
129
- add(key, val)
130
- end
131
- end
132
- end
136
+ alias_method('clear!', 'clear')
133
137
 
134
- alias_method('clear!', 'clear') unless instance_methods.include?('clear!')
135
138
  def clear
136
139
  keep = []
137
140
  depth_first_each do |keys, message|
@@ -147,27 +150,21 @@ module Dao
147
150
  def invalid?(*keys)
148
151
  has?(keys) and !get(keys).nil?
149
152
  end
153
+
150
154
  alias_method('on?', 'invalid?')
151
155
 
152
156
  def on(*args, &block)
153
157
  get(*args, &block)
154
158
  end
155
159
 
156
- def size
157
- size = 0
158
- depth_first_each{ size += 1 }
159
- size
160
- end
161
- alias_method('count', 'size')
162
- alias_method('length', 'size')
163
-
164
160
  def full_messages
165
161
  global_messages = []
166
162
  full_messages = []
167
163
 
168
164
  depth_first_each do |keys, value|
169
165
  index = keys.pop
170
- key = keys.join('.')
166
+ key = keys
167
+ #key = keys.join('.')
171
168
  value = value.to_s
172
169
  next if value.strip.empty?
173
170
  if key == Global
@@ -191,6 +188,7 @@ module Dao
191
188
  def each_full_message
192
189
  full_messages.each{|msg| yield msg}
193
190
  end
191
+
194
192
  alias_method('each_full', 'each_full_message')
195
193
 
196
194
  def messages
@@ -215,25 +213,42 @@ module Dao
215
213
 
216
214
  def Errors.default_errors_to_html(*args)
217
215
  error = args.shift
218
- options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
216
+ options = Map.options_for!(args)
219
217
  errors = [error, *args].flatten.compact
220
218
 
221
219
  at_least_one_error = false
222
- css_class = options[:class] || 'dao errors'
220
+ css_class = options[:class] || 'errors dao'
223
221
 
224
222
  to_html =
225
- table_(:class => css_class){
226
- caption_{ "We're so sorry, but can you please fix the following errors?" }
227
- errors.each do |e|
228
- e.full_messages.each do |key, message|
229
- at_least_one_error = true
230
- tr_{
231
- td_(:class => :key){ key }
232
- td_(:class => :separator){ Separator }
233
- td_(:class => :message){ message }
234
- }
223
+ div_(:class => css_class){
224
+ __
225
+
226
+ div_(:class => :caption){ "We're so sorry, but can you please fix the following errors?" }
227
+ __
228
+
229
+ ul_{
230
+ __
231
+ errors.each do |e|
232
+ e.full_messages.each do |key, message|
233
+ at_least_one_error = true
234
+ title = Array(key).join(' ').titleize
235
+
236
+ error_class = Array(key)==Array(Global) ? "global-error" : "field-error"
237
+ title_class = "title"
238
+ separator_class = "separator"
239
+ message_class = "message"
240
+
241
+ li_(:class => error_class){
242
+ span_(:class => title_class){ title }
243
+ span_(:class => separator_class){ " #{ Separator } " }
244
+ span_(:class => message_class){ message }
245
+ }
246
+ __
247
+ end
235
248
  end
236
- end
249
+ __
250
+ }
251
+ __
237
252
  }
238
253
 
239
254
  at_least_one_error ? to_html : ''