dao 0.0.0 → 2.0.0

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