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.
- 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 : ''
|