dao 0.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +35 -0
- data/Rakefile +6 -3
- data/TODO +37 -0
- data/dao.gemspec +30 -0
- data/db/dao.yml +8 -0
- data/lib/dao.rb +84 -5
- data/lib/dao/active_record.rb +76 -0
- data/lib/dao/api.rb +9 -0
- data/lib/dao/api/context.rb +38 -0
- data/lib/dao/api/dsl.rb +50 -0
- data/lib/dao/api/endpoints.rb +190 -0
- data/lib/dao/api/initializers.rb +71 -0
- data/lib/dao/api/modes.rb +85 -0
- data/lib/dao/blankslate.rb +5 -0
- data/lib/dao/data.rb +58 -0
- data/lib/dao/db.rb +183 -0
- data/lib/dao/endpoint.rb +16 -0
- data/lib/dao/engine.rb +7 -0
- data/lib/dao/errors.rb +238 -0
- data/lib/dao/exceptions.rb +2 -0
- data/lib/dao/form.rb +236 -0
- data/lib/dao/mode.rb +41 -0
- data/lib/dao/mongo_mapper.rb +70 -0
- data/lib/dao/params.rb +109 -0
- data/lib/dao/path.rb +149 -0
- data/lib/dao/rails.rb +15 -0
- data/lib/dao/rails/app/api.rb +55 -0
- data/lib/dao/rails/app/controllers/api_controller.rb +99 -0
- data/lib/dao/rails/lib/generators/dao/USAGE +9 -0
- data/lib/dao/rails/lib/generators/dao/api_generator.rb +3 -0
- data/lib/dao/rails/lib/generators/dao/dao_generator.rb +27 -0
- data/lib/dao/rails/lib/generators/dao/templates/api.rb +55 -0
- data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +99 -0
- data/lib/dao/result.rb +87 -0
- data/lib/dao/slug.rb +11 -0
- data/lib/dao/status.rb +223 -0
- data/lib/dao/stdext.rb +10 -0
- data/lib/dao/support.rb +62 -0
- data/lib/dao/validations.rb +115 -0
- data/sample/rails_app/Gemfile +33 -0
- data/sample/rails_app/Gemfile.lock +88 -0
- data/sample/rails_app/README +1 -0
- data/sample/rails_app/Rakefile +7 -0
- data/sample/rails_app/app/api.rb +55 -0
- data/sample/rails_app/app/controllers/api_controller.rb +99 -0
- data/sample/rails_app/app/controllers/application_controller.rb +3 -0
- data/sample/rails_app/app/helpers/application_helper.rb +2 -0
- data/sample/rails_app/app/views/layouts/application.html.erb +14 -0
- data/sample/rails_app/config.ru +4 -0
- data/sample/rails_app/config/application.rb +51 -0
- data/sample/rails_app/config/boot.rb +13 -0
- data/sample/rails_app/config/database.yml +22 -0
- data/sample/rails_app/config/environment.rb +5 -0
- data/sample/rails_app/config/environments/development.rb +26 -0
- data/sample/rails_app/config/environments/production.rb +49 -0
- data/sample/rails_app/config/environments/test.rb +35 -0
- data/sample/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/sample/rails_app/config/initializers/inflections.rb +10 -0
- data/sample/rails_app/config/initializers/mime_types.rb +5 -0
- data/sample/rails_app/config/initializers/secret_token.rb +7 -0
- data/sample/rails_app/config/initializers/session_store.rb +8 -0
- data/sample/rails_app/config/locales/en.yml +5 -0
- data/sample/rails_app/config/routes.rb +62 -0
- data/sample/rails_app/db/development.sqlite3 +0 -0
- data/sample/rails_app/db/seeds.rb +7 -0
- data/sample/rails_app/doc/README_FOR_APP +2 -0
- data/sample/rails_app/log/development.log +27 -0
- data/sample/rails_app/log/production.log +0 -0
- data/sample/rails_app/log/server.log +0 -0
- data/sample/rails_app/log/test.log +0 -0
- data/sample/rails_app/public/404.html +26 -0
- data/sample/rails_app/public/422.html +26 -0
- data/sample/rails_app/public/500.html +26 -0
- data/sample/rails_app/public/favicon.ico +0 -0
- data/sample/rails_app/public/images/rails.png +0 -0
- data/sample/rails_app/public/index.html +239 -0
- data/sample/rails_app/public/javascripts/application.js +2 -0
- data/sample/rails_app/public/javascripts/controls.js +965 -0
- data/sample/rails_app/public/javascripts/dragdrop.js +974 -0
- data/sample/rails_app/public/javascripts/effects.js +1123 -0
- data/sample/rails_app/public/javascripts/prototype.js +6001 -0
- data/sample/rails_app/public/javascripts/rails.js +175 -0
- data/sample/rails_app/public/robots.txt +5 -0
- data/sample/rails_app/script/rails +6 -0
- data/sample/rails_app/test/performance/browsing_test.rb +9 -0
- data/sample/rails_app/test/test_helper.rb +13 -0
- data/test/dao_test.rb +271 -0
- data/test/helper.rb +15 -0
- data/test/testing.rb +74 -0
- metadata +137 -9
@@ -0,0 +1,71 @@
|
|
1
|
+
module Dao
|
2
|
+
class Api
|
3
|
+
Initializers = {} unless defined?(Initializers)
|
4
|
+
|
5
|
+
class << Api
|
6
|
+
def new(*args, &block)
|
7
|
+
allocate.instance_eval do
|
8
|
+
before_initializers(*args, &block)
|
9
|
+
initialize(*args, &block)
|
10
|
+
after_initializers(*args, &block)
|
11
|
+
self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initializers
|
16
|
+
Initializers[self] ||= {:before => [], :after => []}
|
17
|
+
end
|
18
|
+
|
19
|
+
def before_initializers
|
20
|
+
initializers[:before]
|
21
|
+
end
|
22
|
+
|
23
|
+
def before_initializer(&block)
|
24
|
+
method_name = "before_initializer_#{ before_initializers.size }"
|
25
|
+
define_method(method_name, &block)
|
26
|
+
before_initializers.push(method_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def after_initializers
|
30
|
+
initializers[:after]
|
31
|
+
end
|
32
|
+
|
33
|
+
def after_initializer(&block)
|
34
|
+
after_initializers.push(block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def superclasses
|
38
|
+
@superclasses ||= ancestors.select{|ancestor| ancestor <= Dao::Api}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def superclasses
|
43
|
+
@superclasses ||= self.class.superclasses
|
44
|
+
end
|
45
|
+
|
46
|
+
def run_initializers(which, *args, &block)
|
47
|
+
superclasses.each do |superclass|
|
48
|
+
superclass.send("#{ which }_initializers").each do |method_name|
|
49
|
+
send(method_name, *args, &block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
send("#{ which }_initialize", *args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def before_initializers(*args, &block)
|
56
|
+
run_initializers(:before, *args, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def after_initializers(*args, &block)
|
60
|
+
run_initializers(:after, *args, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def before_initialize(*args, &block)
|
64
|
+
:hook
|
65
|
+
end
|
66
|
+
|
67
|
+
def after_initialize(*args, &block)
|
68
|
+
:hook
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
module Dao
|
3
|
+
class Api
|
4
|
+
class << Api
|
5
|
+
def modes(*modes)
|
6
|
+
@modes ||= []
|
7
|
+
modes.flatten.compact.map{|mode| Api.add_mode(mode)} unless modes.empty?
|
8
|
+
@modes
|
9
|
+
end
|
10
|
+
|
11
|
+
def modes=(*modes)
|
12
|
+
modes(*modes)
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_mode(mode)
|
16
|
+
modes.push(mode = Mode.for(mode)).uniq!
|
17
|
+
|
18
|
+
module_eval(<<-__, __FILE__, __LINE__ - 1)
|
19
|
+
|
20
|
+
def #{ mode }(*args, &block)
|
21
|
+
if args.empty?
|
22
|
+
mode(#{ mode.inspect }, &block)
|
23
|
+
else
|
24
|
+
mode(#{ mode.inspect }) do
|
25
|
+
call(*args, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def #{ mode }?(&block)
|
31
|
+
mode?(#{ mode.inspect }, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
__
|
35
|
+
|
36
|
+
mode
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def mode=(mode)
|
41
|
+
@mode = Mode.for(mode)
|
42
|
+
end
|
43
|
+
|
44
|
+
def mode(*args, &block)
|
45
|
+
@mode ||= Mode.default
|
46
|
+
|
47
|
+
if args.empty? and block.nil?
|
48
|
+
@mode
|
49
|
+
else
|
50
|
+
if block
|
51
|
+
mode = self.mode
|
52
|
+
self.mode = args.shift
|
53
|
+
begin
|
54
|
+
return(instance_eval(&block))
|
55
|
+
ensure
|
56
|
+
self.mode = mode
|
57
|
+
end
|
58
|
+
else
|
59
|
+
self.mode = args.shift
|
60
|
+
return(self)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def mode?(mode, &block)
|
66
|
+
condition = self.mode == mode
|
67
|
+
|
68
|
+
if block.nil?
|
69
|
+
condition
|
70
|
+
else
|
71
|
+
if condition
|
72
|
+
result = block.call
|
73
|
+
throw(:result, result) if catching_the_result?
|
74
|
+
result
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Api.modes = Mode.list
|
81
|
+
|
82
|
+
Api.before_initializer do |*args|
|
83
|
+
@mode = Mode.default
|
84
|
+
end
|
85
|
+
end
|
data/lib/dao/data.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Dao
|
2
|
+
class Data < ::Map
|
3
|
+
add_conversion_method!(:to_dao)
|
4
|
+
add_conversion_method!(:as_dao)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
=begin
|
10
|
+
%w( to_dao as_dao ).each do |method|
|
11
|
+
module_eval <<-__, __FILE__, __LINE__
|
12
|
+
def #{ method }(object, *args, &block)
|
13
|
+
case object
|
14
|
+
when Array
|
15
|
+
object.map{|element| Data.#{ method }(element)}
|
16
|
+
|
17
|
+
else
|
18
|
+
if object.respond_to?(:#{ method })
|
19
|
+
object.send(:#{ method }, *args, &block)
|
20
|
+
else
|
21
|
+
object
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
__
|
26
|
+
end
|
27
|
+
=end
|
28
|
+
|
29
|
+
=begin
|
30
|
+
IdKeys =
|
31
|
+
%w( id uuid guid ).map{|key| [key, key.to_sym, "_#{ key }", "_#{ key }".to_sym]}.flatten
|
32
|
+
|
33
|
+
def id
|
34
|
+
IdKeys.each{|key| return self[key] if has_key?(key)}
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def has_id?
|
39
|
+
IdKeys.each{|key| return true if has_key?(key)}
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
|
43
|
+
def new?
|
44
|
+
!has_id?
|
45
|
+
end
|
46
|
+
|
47
|
+
def new_record?
|
48
|
+
!has_id?
|
49
|
+
end
|
50
|
+
|
51
|
+
def model_name
|
52
|
+
path.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def slug
|
56
|
+
Slug.for(path)
|
57
|
+
end
|
58
|
+
=end
|
data/lib/dao/db.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'yaml/store'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Dao
|
6
|
+
class Db
|
7
|
+
attr_accessor :path
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
options = Dao.options_for!(args)
|
11
|
+
@path = (args.shift || options[:path] || './db/dao.yml').to_s
|
12
|
+
FileUtils.mkdir_p(File.dirname(@path)) rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def db
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def ystore
|
20
|
+
@ystore ||= YAML::Store.new(path)
|
21
|
+
end
|
22
|
+
|
23
|
+
class Collection
|
24
|
+
def initialize(name, db)
|
25
|
+
@name = name.to_s
|
26
|
+
@db = db
|
27
|
+
end
|
28
|
+
|
29
|
+
def save(data = {})
|
30
|
+
@db.save(@name, data)
|
31
|
+
end
|
32
|
+
alias_method(:create, :save)
|
33
|
+
alias_method(:update, :save)
|
34
|
+
|
35
|
+
def find(id = :all)
|
36
|
+
@db.find(@name, id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def all
|
40
|
+
find(:all)
|
41
|
+
end
|
42
|
+
|
43
|
+
def [](id)
|
44
|
+
find(id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete(id)
|
48
|
+
@db.delete(@name, id)
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_hash
|
52
|
+
transaction{|y| y[@name]}
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_yaml(*args, &block)
|
56
|
+
Hash.new.update(to_hash).to_yaml(*args, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def transaction(*args, &block)
|
60
|
+
@db.ystore.transaction(*args, &block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def [](name)
|
65
|
+
Collection.new(name, db)
|
66
|
+
end
|
67
|
+
|
68
|
+
def transaction(*args, &block)
|
69
|
+
ystore.transaction(*args, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
def save(collection, data = {})
|
73
|
+
data = data_for(data)
|
74
|
+
ystore.transaction do |y|
|
75
|
+
collection = (y[collection.to_s] ||= {})
|
76
|
+
id = next_id_for(collection, data)
|
77
|
+
collection[id] = data
|
78
|
+
record = collection[id]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def data_for(data)
|
83
|
+
data ? Map.for(data) : nil
|
84
|
+
end
|
85
|
+
|
86
|
+
alias_method(:create, :save)
|
87
|
+
|
88
|
+
def find(collection, id = :all, &block)
|
89
|
+
ystore.transaction do |y|
|
90
|
+
collection = (y[collection.to_s] ||= {})
|
91
|
+
if id.nil? or id == :all
|
92
|
+
list = collection.values.map{|data| data_for(data)}
|
93
|
+
if block
|
94
|
+
collection[:all] = list.map{|record| data_for(block.call(record))}
|
95
|
+
else
|
96
|
+
list
|
97
|
+
end
|
98
|
+
else
|
99
|
+
key = String(id)
|
100
|
+
record = data_for(collection[key])
|
101
|
+
if block
|
102
|
+
collection[key] = data_for(block.call(record))
|
103
|
+
else
|
104
|
+
record
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def update(collection, id = :all, updates = {})
|
111
|
+
data = data_for(data)
|
112
|
+
find(collection, id) do |record|
|
113
|
+
record.update(updates)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def delete(collection, id = :all)
|
118
|
+
ystore.transaction do |y|
|
119
|
+
collection = (y[collection.to_s] ||= {})
|
120
|
+
if id.nil? or id == :all
|
121
|
+
collection.clear()
|
122
|
+
else
|
123
|
+
deleted = collection.delete(String(id))
|
124
|
+
data_for(deleted) if deleted
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def next_id_for(collection, data)
|
130
|
+
data = data_for(data)
|
131
|
+
begin
|
132
|
+
id = id_for(data)
|
133
|
+
raise if id.strip.empty?
|
134
|
+
id
|
135
|
+
rescue
|
136
|
+
data['id'] = String(collection.size + 1)
|
137
|
+
id_for(data)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def id_for(data)
|
142
|
+
data = data_for(data)
|
143
|
+
%w( id _id ).each{|key| return String(data[key]) if data.has_key?(key)}
|
144
|
+
raise("no id discoverable for #{ data.inspect }")
|
145
|
+
end
|
146
|
+
|
147
|
+
def to_hash
|
148
|
+
ystore.transaction do |y|
|
149
|
+
y.roots.inject(Hash.new){|h,k| h.update(k => y[k])}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_yaml(*args, &block)
|
154
|
+
to_hash.to_yaml(*args, &block)
|
155
|
+
end
|
156
|
+
|
157
|
+
class << Db
|
158
|
+
attr_writer :root
|
159
|
+
attr_writer :instance
|
160
|
+
|
161
|
+
def default_root()
|
162
|
+
defined?(Rails.root) ? File.join(Rails.root.to_s, 'db') : './db'
|
163
|
+
end
|
164
|
+
|
165
|
+
def default_path()
|
166
|
+
File.join(default_root, 'dao.yml')
|
167
|
+
end
|
168
|
+
|
169
|
+
def method_missing(method, *args, &block)
|
170
|
+
super unless instance.respond_to?(method)
|
171
|
+
instance.send(method, *args, &block)
|
172
|
+
end
|
173
|
+
|
174
|
+
def instance
|
175
|
+
@instance ||= Db.new(Db.default_path)
|
176
|
+
end
|
177
|
+
|
178
|
+
def root
|
179
|
+
@root ||= default_root
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
data/lib/dao/endpoint.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Dao
|
2
|
+
class Endpoint
|
3
|
+
Attrs = %w( api path method doc )
|
4
|
+
Attrs.each{|attr| attr_accessor(attr)}
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
update(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def update(options = {})
|
11
|
+
options.each do |key, val|
|
12
|
+
send("#{ key }=", val)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/dao/engine.rb
ADDED
data/lib/dao/errors.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
module Dao
|
2
|
+
class Errors < ::Map
|
3
|
+
Global = '*' unless defined?(Global)
|
4
|
+
Separator = ':' unless defined?(Separator)
|
5
|
+
|
6
|
+
class Message < ::String
|
7
|
+
attr_accessor :sticky
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
|
11
|
+
replace(args.join(' '))
|
12
|
+
@sticky = options[:sticky]
|
13
|
+
end
|
14
|
+
|
15
|
+
def sticky?
|
16
|
+
@sticky ||= nil
|
17
|
+
!!@sticky
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class << Errors
|
22
|
+
def global_key
|
23
|
+
[Global]
|
24
|
+
end
|
25
|
+
|
26
|
+
def for(*args, &block)
|
27
|
+
new(*args, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def cast(*args)
|
31
|
+
if args.size == 1
|
32
|
+
value = args.first
|
33
|
+
value.is_a?(self) ? value : self.for(value)
|
34
|
+
else
|
35
|
+
self.for(*args)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def add(*args)
|
41
|
+
options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
|
42
|
+
sticky = options[:sticky]
|
43
|
+
clear = options[:clear]
|
44
|
+
|
45
|
+
args.flatten!
|
46
|
+
message = args.pop
|
47
|
+
keys = args
|
48
|
+
keys = [Global] if keys.empty?
|
49
|
+
errors = Hash.new
|
50
|
+
|
51
|
+
if Array(keys) == [Global]
|
52
|
+
sticky = true unless options.has_key?(:sticky)
|
53
|
+
end
|
54
|
+
|
55
|
+
sticky = true if(message.respond_to?(:sticky?) and message.sticky?)
|
56
|
+
|
57
|
+
if message
|
58
|
+
if message.respond_to?(:full_messages)
|
59
|
+
message.depth_first_each do |keys, msg|
|
60
|
+
errors[keys] = Message.new(msg, :sticky => sticky)
|
61
|
+
end
|
62
|
+
else
|
63
|
+
errors[keys] = Message.new(message, :sticky => sticky)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
result = []
|
68
|
+
|
69
|
+
errors.each do |keys, message|
|
70
|
+
list = get(keys)
|
71
|
+
unless get(keys)
|
72
|
+
set(keys => [])
|
73
|
+
list = get(keys)
|
74
|
+
end
|
75
|
+
list.clear if clear
|
76
|
+
list.push(message)
|
77
|
+
result = list
|
78
|
+
end
|
79
|
+
|
80
|
+
result
|
81
|
+
end
|
82
|
+
alias_method 'add_to_base', 'add'
|
83
|
+
|
84
|
+
def clone
|
85
|
+
clone = Errors.new
|
86
|
+
depth_first_each do |keys, message|
|
87
|
+
args = [*keys]
|
88
|
+
args.push(message)
|
89
|
+
clone.add(*args)
|
90
|
+
end
|
91
|
+
clone
|
92
|
+
end
|
93
|
+
|
94
|
+
def add!(*args)
|
95
|
+
options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
|
96
|
+
options[:sticky] = true
|
97
|
+
args.push(options)
|
98
|
+
add(*args)
|
99
|
+
end
|
100
|
+
alias_method 'add_to_base!', 'add!'
|
101
|
+
|
102
|
+
alias_method 'clear!', 'clear' unless instance_methods.include?('clear!')
|
103
|
+
|
104
|
+
def update(other, options = {})
|
105
|
+
options = Dao.map_for(options)
|
106
|
+
prefix = Array(options[:prefix]).flatten.compact
|
107
|
+
|
108
|
+
other.each do |key, val|
|
109
|
+
key = key.to_s
|
110
|
+
if key == 'base' or key == Global
|
111
|
+
add!(val)
|
112
|
+
else
|
113
|
+
key = prefix + [key] unless prefix.empty?
|
114
|
+
add(key, val)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def clear
|
120
|
+
keep = []
|
121
|
+
depth_first_each do |keys, message|
|
122
|
+
index = keys.pop
|
123
|
+
args = [keys, message].flatten
|
124
|
+
keep.push(args) if message.sticky?
|
125
|
+
end
|
126
|
+
clear!
|
127
|
+
ensure
|
128
|
+
keep.each{|args| add!(*args)}
|
129
|
+
end
|
130
|
+
|
131
|
+
def invalid?(*keys)
|
132
|
+
!get(keys).nil?
|
133
|
+
end
|
134
|
+
|
135
|
+
alias_method 'on?', 'invalid?'
|
136
|
+
|
137
|
+
alias_method 'on', 'get'
|
138
|
+
|
139
|
+
def size
|
140
|
+
size = 0
|
141
|
+
depth_first_each{ size += 1 }
|
142
|
+
size
|
143
|
+
end
|
144
|
+
|
145
|
+
alias_method 'count', 'size'
|
146
|
+
alias_method 'length', 'size'
|
147
|
+
|
148
|
+
def full_messages
|
149
|
+
full_messages = []
|
150
|
+
|
151
|
+
depth_first_each do |keys, value|
|
152
|
+
index = keys.pop
|
153
|
+
key = keys.join('.')
|
154
|
+
value = value.to_s
|
155
|
+
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
|
165
|
+
else
|
166
|
+
a <=> b
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
full_messages
|
171
|
+
end
|
172
|
+
|
173
|
+
def each_message
|
174
|
+
depth_first_each do |keys, message|
|
175
|
+
index = keys.pop
|
176
|
+
message = message.to_s.strip
|
177
|
+
next if message.empty?
|
178
|
+
yield(keys, message)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def each_full_message
|
183
|
+
full_messages.each{|msg| yield msg}
|
184
|
+
end
|
185
|
+
|
186
|
+
alias_method 'each_full', 'each_full_message'
|
187
|
+
|
188
|
+
def messages
|
189
|
+
messages =
|
190
|
+
(self[Global]||[]).map{|message| message}.
|
191
|
+
select{|message| not message.strip.empty?}
|
192
|
+
end
|
193
|
+
|
194
|
+
def to_html(*args)
|
195
|
+
Errors.to_html(errors=self, *args)
|
196
|
+
end
|
197
|
+
|
198
|
+
def Errors.to_html(*args, &block)
|
199
|
+
if block
|
200
|
+
define_method(:to_html, &block)
|
201
|
+
else
|
202
|
+
default_errors_to_html(*args)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def Errors.default_errors_to_html(*args)
|
207
|
+
error = args.shift
|
208
|
+
options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
|
209
|
+
errors = [error, *args].flatten.compact
|
210
|
+
|
211
|
+
at_least_one = false
|
212
|
+
css_class = options[:class] || 'dao errors'
|
213
|
+
|
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>")
|
227
|
+
end
|
228
|
+
end
|
229
|
+
html.push("</table>")
|
230
|
+
|
231
|
+
at_least_one ? html.join("\n") : ''
|
232
|
+
end
|
233
|
+
|
234
|
+
def to_s(*args, &block)
|
235
|
+
to_html(*args, &block)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|