dao 0.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/README +35 -0
  2. data/Rakefile +6 -3
  3. data/TODO +37 -0
  4. data/dao.gemspec +30 -0
  5. data/db/dao.yml +8 -0
  6. data/lib/dao.rb +84 -5
  7. data/lib/dao/active_record.rb +76 -0
  8. data/lib/dao/api.rb +9 -0
  9. data/lib/dao/api/context.rb +38 -0
  10. data/lib/dao/api/dsl.rb +50 -0
  11. data/lib/dao/api/endpoints.rb +190 -0
  12. data/lib/dao/api/initializers.rb +71 -0
  13. data/lib/dao/api/modes.rb +85 -0
  14. data/lib/dao/blankslate.rb +5 -0
  15. data/lib/dao/data.rb +58 -0
  16. data/lib/dao/db.rb +183 -0
  17. data/lib/dao/endpoint.rb +16 -0
  18. data/lib/dao/engine.rb +7 -0
  19. data/lib/dao/errors.rb +238 -0
  20. data/lib/dao/exceptions.rb +2 -0
  21. data/lib/dao/form.rb +236 -0
  22. data/lib/dao/mode.rb +41 -0
  23. data/lib/dao/mongo_mapper.rb +70 -0
  24. data/lib/dao/params.rb +109 -0
  25. data/lib/dao/path.rb +149 -0
  26. data/lib/dao/rails.rb +15 -0
  27. data/lib/dao/rails/app/api.rb +55 -0
  28. data/lib/dao/rails/app/controllers/api_controller.rb +99 -0
  29. data/lib/dao/rails/lib/generators/dao/USAGE +9 -0
  30. data/lib/dao/rails/lib/generators/dao/api_generator.rb +3 -0
  31. data/lib/dao/rails/lib/generators/dao/dao_generator.rb +27 -0
  32. data/lib/dao/rails/lib/generators/dao/templates/api.rb +55 -0
  33. data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +99 -0
  34. data/lib/dao/result.rb +87 -0
  35. data/lib/dao/slug.rb +11 -0
  36. data/lib/dao/status.rb +223 -0
  37. data/lib/dao/stdext.rb +10 -0
  38. data/lib/dao/support.rb +62 -0
  39. data/lib/dao/validations.rb +115 -0
  40. data/sample/rails_app/Gemfile +33 -0
  41. data/sample/rails_app/Gemfile.lock +88 -0
  42. data/sample/rails_app/README +1 -0
  43. data/sample/rails_app/Rakefile +7 -0
  44. data/sample/rails_app/app/api.rb +55 -0
  45. data/sample/rails_app/app/controllers/api_controller.rb +99 -0
  46. data/sample/rails_app/app/controllers/application_controller.rb +3 -0
  47. data/sample/rails_app/app/helpers/application_helper.rb +2 -0
  48. data/sample/rails_app/app/views/layouts/application.html.erb +14 -0
  49. data/sample/rails_app/config.ru +4 -0
  50. data/sample/rails_app/config/application.rb +51 -0
  51. data/sample/rails_app/config/boot.rb +13 -0
  52. data/sample/rails_app/config/database.yml +22 -0
  53. data/sample/rails_app/config/environment.rb +5 -0
  54. data/sample/rails_app/config/environments/development.rb +26 -0
  55. data/sample/rails_app/config/environments/production.rb +49 -0
  56. data/sample/rails_app/config/environments/test.rb +35 -0
  57. data/sample/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  58. data/sample/rails_app/config/initializers/inflections.rb +10 -0
  59. data/sample/rails_app/config/initializers/mime_types.rb +5 -0
  60. data/sample/rails_app/config/initializers/secret_token.rb +7 -0
  61. data/sample/rails_app/config/initializers/session_store.rb +8 -0
  62. data/sample/rails_app/config/locales/en.yml +5 -0
  63. data/sample/rails_app/config/routes.rb +62 -0
  64. data/sample/rails_app/db/development.sqlite3 +0 -0
  65. data/sample/rails_app/db/seeds.rb +7 -0
  66. data/sample/rails_app/doc/README_FOR_APP +2 -0
  67. data/sample/rails_app/log/development.log +27 -0
  68. data/sample/rails_app/log/production.log +0 -0
  69. data/sample/rails_app/log/server.log +0 -0
  70. data/sample/rails_app/log/test.log +0 -0
  71. data/sample/rails_app/public/404.html +26 -0
  72. data/sample/rails_app/public/422.html +26 -0
  73. data/sample/rails_app/public/500.html +26 -0
  74. data/sample/rails_app/public/favicon.ico +0 -0
  75. data/sample/rails_app/public/images/rails.png +0 -0
  76. data/sample/rails_app/public/index.html +239 -0
  77. data/sample/rails_app/public/javascripts/application.js +2 -0
  78. data/sample/rails_app/public/javascripts/controls.js +965 -0
  79. data/sample/rails_app/public/javascripts/dragdrop.js +974 -0
  80. data/sample/rails_app/public/javascripts/effects.js +1123 -0
  81. data/sample/rails_app/public/javascripts/prototype.js +6001 -0
  82. data/sample/rails_app/public/javascripts/rails.js +175 -0
  83. data/sample/rails_app/public/robots.txt +5 -0
  84. data/sample/rails_app/script/rails +6 -0
  85. data/sample/rails_app/test/performance/browsing_test.rb +9 -0
  86. data/sample/rails_app/test/test_helper.rb +13 -0
  87. data/test/dao_test.rb +271 -0
  88. data/test/helper.rb +15 -0
  89. data/test/testing.rb +74 -0
  90. 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
@@ -0,0 +1,5 @@
1
+ module Dao
2
+ class BlankSlate
3
+ instance_methods.each{|m| undef_method(m) unless m.to_s =~ /(^__)|object_id/}
4
+ end
5
+ 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
@@ -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
@@ -0,0 +1,7 @@
1
+ module Dao
2
+ if(defined?(Rails) && Rails::VERSION::MAJOR == 3)
3
+ class Engine < Rails::Engine
4
+ engine_name :dao
5
+ end
6
+ end
7
+ end
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