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
data/lib/dao/result.rb ADDED
@@ -0,0 +1,87 @@
1
+ module Dao
2
+ class Result < ::Map
3
+ attr_accessor :api
4
+ attr_accessor :endpoint
5
+ attr_accessor :params
6
+ attr_accessor :validations
7
+ attr_accessor :form
8
+
9
+ def Result.for(*args, &block)
10
+ new(*args, &block)
11
+ end
12
+
13
+ def initialize(*args, &block)
14
+ options = Dao.options_for!(args)
15
+ args.push('/dao') if args.empty?
16
+
17
+ path = Path.for(*args)
18
+ status = Status.ok
19
+ errors = Errors.new
20
+ data = Data.new
21
+
22
+ api = options[:api]
23
+ endpoint = options[:endpoint]
24
+ params = options[:params] || Params.new
25
+
26
+ path = endpoint.path if endpoint
27
+
28
+ form = Form.for(self)
29
+ validations = Validations.for(self)
30
+
31
+ self[:path] = path
32
+ self[:status] = status
33
+ self[:errors] = errors
34
+ self[:data] = data
35
+
36
+ @api = api
37
+ @endpoint = endpoint
38
+ @params = params
39
+ @form = form
40
+ @validations = validations
41
+ end
42
+
43
+ def path
44
+ self[:path]
45
+ end
46
+
47
+ def status(*args)
48
+ self[:status] = Status.for(*args) unless args.empty?
49
+ self[:status]
50
+ end
51
+ def status=(value)
52
+ status(value)
53
+ end
54
+
55
+ def errors
56
+ self[:errors]
57
+ end
58
+
59
+ def data
60
+ self[:data]
61
+ end
62
+
63
+ def validates(*args, &block)
64
+ validations.add(*args, &block)
65
+ end
66
+
67
+ def validate(*args, &block)
68
+ if !args.empty?
69
+ validates(*args, &block)
70
+ else
71
+ validations.run
72
+ #status(420) if(status.ok? and !errors.empty?)
73
+ errors.empty? and status.ok?
74
+ end
75
+ end
76
+
77
+ def valid?
78
+ validate
79
+ end
80
+
81
+ def validate!
82
+ validations.run!
83
+ #status(420) if(status.ok? and !errors.empty?)
84
+ throw(:result, nil) unless(errors.empty? and status.ok?)
85
+ end
86
+ end
87
+ end
data/lib/dao/slug.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Dao
2
+ class Slug < ::String
3
+ def Slug.for(*args)
4
+ string = args.flatten.compact.join('-')
5
+ words = string.to_s.scan(%r/\w+/)
6
+ words.map!{|word| word.gsub(%r/[^0-9a-zA-Z_-]/, '')}
7
+ words.delete_if{|word| word.nil? or word.strip.empty?}
8
+ new(words.join('-').downcase)
9
+ end
10
+ end
11
+ end
data/lib/dao/status.rb ADDED
@@ -0,0 +1,223 @@
1
+ module Dao
2
+ class Status < ::String
3
+ Code2Message = (
4
+ {
5
+ 100 => "Continue",
6
+ 101 => "Switching Protocols",
7
+ 102 => "Processing",
8
+
9
+ 200 => "OK",
10
+ 201 => "Created",
11
+ 202 => "Accepted",
12
+ 203 => "Non-Authoritative Information",
13
+ 204 => "No Content",
14
+ 205 => "Reset Content",
15
+ 206 => "Partial Content",
16
+ 207 => "Multi-Status",
17
+ 226 => "IM Used",
18
+
19
+ 300 => "Multiple Choices",
20
+ 301 => "Moved Permanently",
21
+ 302 => "Found",
22
+ 303 => "See Other",
23
+ 304 => "Not Modified",
24
+ 305 => "Use Proxy",
25
+ 307 => "Temporary Redirect",
26
+
27
+ 400 => "Bad Request",
28
+ 401 => "Unauthorized",
29
+ 402 => "Payment Required",
30
+ 403 => "Forbidden",
31
+ 404 => "Not Found",
32
+ 405 => "Method Not Allowed",
33
+ 406 => "Not Acceptable",
34
+ 407 => "Proxy Authentication Required",
35
+ 408 => "Request Timeout",
36
+ 409 => "Conflict",
37
+ 410 => "Gone",
38
+ 411 => "Length Required",
39
+ 412 => "Precondition Failed",
40
+ 413 => "Request Entity Too Large",
41
+ 414 => "Request-URI Too Long",
42
+ 415 => "Unsupported Media Type",
43
+ 416 => "Requested Range Not Satisfiable",
44
+ 417 => "Expectation Failed",
45
+ 420 => "Enhance Your Calm",
46
+ 422 => "Unprocessable Entity",
47
+ 423 => "Locked",
48
+ 424 => "Failed Dependency",
49
+ 426 => "Upgrade Required",
50
+
51
+ 500 => "Internal Server Error",
52
+ 501 => "Not Implemented",
53
+ 502 => "Bad Gateway",
54
+ 503 => "Service Unavailable",
55
+ 504 => "Gateway Timeout",
56
+ 505 => "HTTP Version Not Supported",
57
+ 507 => "Insufficient Storage",
58
+ 510 => "Not Extended"
59
+ }
60
+ ) unless defined?(Code2Message)
61
+
62
+ def Status.underscore(camel_cased_word)
63
+ camel_cased_word.to_s.gsub(/::/, '/').
64
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
65
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
66
+ #gsub(/\s+/, '').
67
+ tr("-", "_").
68
+ downcase
69
+ end
70
+
71
+ Symbol2Code = (
72
+ Code2Message.inject(Hash.new) do |hash, (code, message)|
73
+ sym = Status.underscore(message.gsub(/\s+/, "")).to_sym
74
+ hash.update(sym => code)
75
+ end
76
+ ) unless defined?(Symbol2Code)
77
+
78
+ Symbol2Code.each do |sym, code|
79
+ module_eval <<-__
80
+ def Status.#{ sym }()
81
+ @#{ sym } ||= Status.for(:#{ sym })
82
+ end
83
+ __
84
+ end
85
+
86
+ attr :code
87
+ attr :message
88
+ attr :group
89
+
90
+ def initialize(*args)
91
+ code, message =
92
+ if args.size == 2
93
+ [args.first, args.last]
94
+ else
95
+ status = Status.for(args.first || 200)
96
+ [status.code, status.message]
97
+ end
98
+ @code, @message = Integer(code), String(message)
99
+ @group = (@code / 100) * 100
100
+ replace("#{ @code } #{ @message }".strip)
101
+ end
102
+
103
+ Groups = ({
104
+ 100 => 'instruction',
105
+ 200 => 'success',
106
+ 300 => 'redirection',
107
+ 400 => 'client_error',
108
+ 500 => 'server_error'
109
+ }) unless defined?(Groups)
110
+
111
+ Groups.each do |code, group|
112
+ module_eval <<-__
113
+ def #{ group }?()
114
+ #{ code } == @group
115
+ end
116
+ __
117
+ end
118
+
119
+ def Status.list
120
+ @list ||= Symbol2Code.sort_by{|sym, code| code}.map{|sym, code| send(sym)}
121
+ end
122
+
123
+ def good?
124
+ @group < 400
125
+ end
126
+ alias_method 'ok?', 'good?'
127
+
128
+ def bad?
129
+ @group >= 400
130
+ end
131
+ alias_method 'error?', 'bad?'
132
+
133
+ def ==(other)
134
+ begin
135
+ other = Status.for(other)
136
+ self.code == other.code and self.message == other.message
137
+ rescue
138
+ false
139
+ end
140
+ end
141
+
142
+ def clone
143
+ clone = Status.for(code)
144
+ end
145
+
146
+ def to_json(*args, &block)
147
+ Map[:code, code, :message, message].to_json(*args, &block)
148
+ end
149
+
150
+ class << Status
151
+ def for(*args)
152
+ if args.size >= 2
153
+ code = args.shift
154
+ message = args.join(' ')
155
+ new(code, message)
156
+ else
157
+ arg = args.shift
158
+ case arg
159
+ when Result
160
+ result = arg
161
+ if arg.errors.nil? or arg.errors.empty? or arg.valid?
162
+ new(200)
163
+ else
164
+ new(500)
165
+ end
166
+ when Status
167
+ arg
168
+ when Fixnum
169
+ code = arg
170
+ message = Code2Message[code]
171
+ new(code, message)
172
+ when Symbol, String
173
+ sym = Status.underscore(arg).to_sym
174
+ code = Symbol2Code[sym]
175
+ if code
176
+ message = Code2Message[code]
177
+ else
178
+ code = 500
179
+ message = "Unknown Status #{ arg }"
180
+ end
181
+ new(code, message)
182
+ else
183
+ if arg.respond_to?(:code) and arg.respond_to?(:message)
184
+ code, message = arg.code, arg.message
185
+ new(code, message)
186
+ else
187
+ parse(arg)
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ def parse(string)
194
+ first, last = string.to_s.strip.split(%r/\s+/, 2)
195
+ if first =~ %r/^\d+$/
196
+ code = Integer(first)
197
+ message = last
198
+ else
199
+ code = 500
200
+ message = "Unknown Status #{ string.inspect }"
201
+ end
202
+ new(code, message)
203
+ end
204
+
205
+ def cast(*args)
206
+ if args.size == 1
207
+ value = args.first
208
+ value.is_a?(self) ? value : self.for(value)
209
+ else
210
+ self.for(*args)
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ def Dao.status(*args, &block)
217
+ if args.empty? and block.nil?
218
+ Status
219
+ else
220
+ Status.for(*args, &block)
221
+ end
222
+ end
223
+ end
data/lib/dao/stdext.rb ADDED
@@ -0,0 +1,10 @@
1
+ class Array
2
+ def to_dao(*args, &block)
3
+ Dao.to_dao(self, *args, &block)
4
+ end
5
+
6
+ def as_dao(*args, &block)
7
+ Dao.as_dao(self, *args, &block)
8
+ end
9
+ end
10
+
@@ -0,0 +1,62 @@
1
+ module Dao
2
+ def map_for(*args, &block)
3
+ Map.for(*args, &block)
4
+ end
5
+ alias_method(:map, :map_for)
6
+ alias_method(:hash, :map_for)
7
+
8
+ def options_for!(args)
9
+ Map.options_for!(args)
10
+ end
11
+
12
+ def options_for(args)
13
+ Map.options_for(args)
14
+ end
15
+
16
+ def db(*args, &block)
17
+ if args.empty? and block.nil?
18
+ Db.instance
19
+ else
20
+ method = args.shift
21
+ Db.instance.send(method, *args, &block)
22
+ end
23
+ end
24
+
25
+ %w( to_dao as_dao ).each do |method|
26
+
27
+ module_eval <<-__, __FILE__, __LINE__ - 1
28
+
29
+ def #{ method }(object, *args, &block)
30
+ case object
31
+ when Array
32
+ object.map{|element| Dao.#{ method }(element)}
33
+
34
+ else
35
+ if object.respond_to?(:#{ method })
36
+ object.send(:#{ method }, *args, &block)
37
+ else
38
+ object
39
+ end
40
+ end
41
+ end
42
+
43
+ __
44
+ end
45
+
46
+
47
+ def unindent!(s)
48
+ margin = nil
49
+ s.each do |line|
50
+ next if line =~ %r/^\s*$/
51
+ margin = line[%r/^\s*/] and break
52
+ end
53
+ s.gsub! %r/^#{ margin }/, "" if margin
54
+ margin ? s : nil
55
+ end
56
+
57
+ def unindent(s)
58
+ s = "#{ s }"
59
+ unindent!(s)
60
+ s
61
+ end
62
+ end
@@ -0,0 +1,115 @@
1
+ module Dao
2
+ class Validations < ::Map
3
+ class Callback < ::Proc
4
+ attr :options
5
+
6
+ def initialize(options = {}, &block)
7
+ @options = Dao.map_for(options || {})
8
+ super(&block)
9
+ end
10
+
11
+ def block
12
+ self
13
+ end
14
+ end
15
+
16
+ class << Validations
17
+ def for(*args, &block)
18
+ new(*args, &block)
19
+ end
20
+
21
+ def cast(*args)
22
+ if args.size == 1
23
+ value = args.first
24
+ value.is_a?(self) ? value : self.for(value)
25
+ else
26
+ self.for(*args)
27
+ end
28
+ end
29
+ end
30
+
31
+ attr_accessor :result
32
+
33
+ def initialize(*args, &block)
34
+ @result = args.shift if args.first.is_a?(Result)
35
+ super
36
+ end
37
+
38
+ def params
39
+ result.params
40
+ end
41
+
42
+ def errors
43
+ result.errors
44
+ end
45
+
46
+ def each(&block)
47
+ depth_first_each(&block)
48
+ end
49
+
50
+ def size
51
+ size = 0
52
+ depth_first_each{ size += 1 }
53
+ size
54
+ end
55
+
56
+ alias_method 'count', 'size'
57
+ alias_method 'length', 'size'
58
+
59
+ Cleared = '___CLEARED___'.freeze unless defined?(Cleared)
60
+
61
+ def run
62
+ previous_errors = []
63
+ new_errors = []
64
+
65
+ errors.each_message do |keys, message|
66
+ previous_errors.push([keys, message])
67
+ end
68
+
69
+ errors.clear
70
+
71
+ depth_first_each do |keys, callback|
72
+ next unless callback and callback.respond_to?(:to_proc)
73
+
74
+ value = params.get(keys)
75
+ valid = !!callback.call(value)
76
+ #valid = !!params.instance_exec(value, &callback)
77
+ message = callback.options[:message] || (value.nil? ? 'is blank.' : 'is invalid.')
78
+
79
+ unless valid
80
+ new_errors.push([keys, message])
81
+ else
82
+ new_errors.push([keys, Cleared])
83
+ end
84
+ end
85
+
86
+ previous_errors.each do |keys, message|
87
+ errors.add(keys, message) unless new_errors.assoc(keys)
88
+ end
89
+
90
+ new_errors.each do |keys, value|
91
+ next if value == Cleared
92
+ message = value
93
+ errors.add(keys, message)
94
+ end
95
+
96
+ return self
97
+ end
98
+
99
+ def run!
100
+ errors.clear!
101
+ run
102
+ end
103
+
104
+ NotNil = lambda{|value| !value.nil?}
105
+
106
+ def add(*args, &block)
107
+ options = Dao.map_for(args.last.is_a?(Hash) ? args.pop : {})
108
+ block = args.pop if args.last.respond_to?(:call)
109
+ block ||= NotNil
110
+ callback = Validations::Callback.new(options, &block)
111
+ args.push(callback)
112
+ set(*args)
113
+ end
114
+ end
115
+ end