dao 3.3.0 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
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 : ''