dao 3.3.0 → 4.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +7 -0
- data/Rakefile +36 -17
- data/b.rb +38 -0
- data/dao.gemspec +41 -13
- data/lib/dao.rb +44 -13
- data/lib/dao/api.rb +1 -1
- data/lib/dao/api/context.rb +35 -45
- data/lib/dao/api/endpoints.rb +225 -91
- data/lib/dao/conducer.rb +437 -0
- data/lib/dao/conducer/attributes.rb +21 -0
- data/lib/dao/conducer/crud.rb +70 -0
- data/lib/dao/current.rb +66 -0
- data/lib/dao/db.rb +44 -5
- data/lib/dao/endpoint.rb +13 -1
- data/lib/dao/errors.rb +74 -59
- data/lib/dao/exceptions.rb +1 -2
- data/lib/dao/extractor.rb +68 -0
- data/lib/dao/form.rb +139 -46
- data/lib/dao/image_cache.rb +193 -0
- data/lib/dao/instance_exec.rb +1 -1
- data/lib/dao/name.rb +7 -0
- data/lib/dao/params.rb +16 -66
- data/lib/dao/rack.rb +3 -0
- data/lib/dao/rack/middleware.rb +5 -0
- data/lib/dao/rack/middleware/params_parser.rb +24 -0
- data/lib/dao/rails.rb +22 -5
- data/lib/dao/rails/lib/generators/dao/USAGE +2 -6
- data/lib/dao/rails/lib/generators/dao/dao_generator.rb +52 -7
- data/lib/dao/rails/lib/generators/dao/templates/api.rb +23 -7
- data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +24 -7
- data/lib/dao/rails/lib/generators/dao/templates/conducer.rb +64 -0
- data/lib/dao/rails/lib/generators/dao/templates/conducer_controller.rb +79 -0
- data/lib/dao/rails/lib/generators/dao/templates/dao.js +13 -6
- data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +75 -11
- data/lib/dao/result.rb +1 -26
- data/lib/dao/slug.rb +37 -8
- data/lib/dao/status.rb +4 -0
- data/lib/dao/support.rb +155 -0
- data/lib/dao/validations.rb +48 -157
- data/lib/dao/validations/callback.rb +30 -0
- data/lib/dao/validations/common.rb +322 -320
- data/lib/dao/validations/validator.rb +219 -0
- data/test/active_model_conducer_lint_test.rb +19 -0
- data/test/api_test.rb +261 -0
- data/test/conducer_test.rb +205 -0
- data/test/db.yml +9 -0
- data/test/form_test.rb +42 -0
- data/test/support_test.rb +52 -0
- data/test/testing.rb +145 -24
- data/test/validations_test.rb +156 -0
- metadata +138 -21
- data/TODO +0 -33
- data/a.rb +0 -80
- data/db/dao.yml +0 -5
- data/lib/dao/api/interfaces.rb +0 -306
- data/lib/dao/interface.rb +0 -28
- data/lib/dao/presenter.rb +0 -129
- data/lib/dao/rails/lib/generators/dao/api_generator.rb +0 -3
- data/lib/dao/validations/base.rb +0 -68
- 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
|
data/lib/dao/current.rb
ADDED
@@ -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 =
|
11
|
-
@path = (args.shift || options[:path] ||
|
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, '
|
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
|
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 =
|
15
|
-
Separator = "
|
16
|
-
|
21
|
+
#Separator = "\342\207\222" unless defined?(Separator) ### this is an "Open-outlined rightward arrow"
|
22
|
+
Separator = ":" unless defined?(Separator)
|
17
23
|
|
18
|
-
#
|
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 =
|
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 =
|
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
|
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 =
|
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
|
-
|
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
|
-
|
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
|
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 =
|
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
|
220
|
+
css_class = options[:class] || 'errors dao'
|
223
221
|
|
224
222
|
to_html =
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
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
|
-
|
249
|
+
__
|
250
|
+
}
|
251
|
+
__
|
237
252
|
}
|
238
253
|
|
239
254
|
at_least_one_error ? to_html : ''
|