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
data/lib/dao/instance_exec.rb
CHANGED
data/lib/dao/name.rb
ADDED
data/lib/dao/params.rb
CHANGED
@@ -2,87 +2,37 @@ module Dao
|
|
2
2
|
class Params < ::Map
|
3
3
|
# mixins
|
4
4
|
#
|
5
|
-
include Validations
|
5
|
+
include Validations
|
6
6
|
|
7
7
|
# class methods
|
8
8
|
#
|
9
9
|
class << Params
|
10
|
-
def parse(prefix, params = {}, options = {})
|
11
|
-
prefix = prefix.to_s
|
12
|
-
params = Map.new(params || {})
|
13
|
-
base = Map.new(params || {})
|
14
|
-
options = Map.options(options || {})
|
15
|
-
parsed = Params.new
|
16
|
-
parsed.update(params[prefix]) if params.has_key?(prefix)
|
17
|
-
|
18
|
-
re = %r/^ #{ Regexp.escape(prefix) } (?: [(] ([^)]+) [)] )? $/x
|
19
|
-
|
20
|
-
params.each do |key, value|
|
21
|
-
next unless(key.is_a?(String) or key.is_a?(Symbol))
|
22
|
-
key = key.to_s
|
23
|
-
matched, keys = re.match(key).to_a
|
24
|
-
next unless matched
|
25
|
-
next unless keys
|
26
|
-
keys = keys_for(keys)
|
27
|
-
parsed.set(keys => value)
|
28
|
-
base.delete(key)
|
29
|
-
end
|
30
|
-
|
31
|
-
whitelist = Set.new( [options.getopt([:include, :select, :only])].flatten.compact.map{|k| k.to_s} )
|
32
|
-
blacklist = Set.new( [options.getopt([:exclude, :reject, :except])].flatten.compact.map{|k| k.to_s} )
|
33
|
-
|
34
|
-
unless blacklist.empty?
|
35
|
-
base.keys.dup.each do |key|
|
36
|
-
base.delete(key) if blacklist.include?(key.to_s)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
unless whitelist.empty?
|
41
|
-
base.keys.dup.each do |key|
|
42
|
-
base.delete(key) unless whitelist.include?(key.to_s)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
if options.getopt(:fold, default=true)
|
47
|
-
parsed_and_folded = base.merge(parsed)
|
48
|
-
else
|
49
|
-
parsed
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def keys_for(keys)
|
54
|
-
keys.strip.split(%r/\s*,\s*/).map{|key| key =~ %r/^\d+$/ ? Integer(key) : key}
|
55
|
-
end
|
56
|
-
|
57
|
-
def process(path, params, options = {})
|
58
|
-
return params if params.is_a?(Params)
|
59
|
-
|
60
|
-
parsed = Params.parse(path, params, options)
|
61
|
-
return parsed unless parsed.empty?
|
62
|
-
|
63
|
-
return Params.new(params)
|
64
|
-
end
|
65
10
|
end
|
66
11
|
|
67
12
|
# instance methods
|
68
13
|
#
|
69
|
-
attr_accessor :result
|
70
|
-
attr_accessor :route
|
71
14
|
attr_accessor :path
|
72
|
-
attr_accessor :
|
73
|
-
attr_accessor :errors
|
74
|
-
attr_accessor :validations
|
15
|
+
attr_accessor :route
|
75
16
|
attr_accessor :form
|
76
17
|
|
77
18
|
def initialize(*args, &block)
|
78
|
-
|
79
|
-
|
80
|
-
@
|
81
|
-
@
|
82
|
-
@form = Form.for(self)
|
19
|
+
options = Dao.options_for!(args)
|
20
|
+
|
21
|
+
@path = args.shift || options[:path] || Path.default
|
22
|
+
@route = options[:route] || Route.default
|
23
|
+
@form = options[:form] || Form.for(self)
|
24
|
+
|
25
|
+
update(options[:params]) if options[:params]
|
26
|
+
|
83
27
|
super
|
84
28
|
end
|
85
29
|
|
30
|
+
def attributes
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
fattr(:name){ path }
|
35
|
+
|
86
36
|
# look good for inspect
|
87
37
|
#
|
88
38
|
def inspect
|
data/lib/dao/rack.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Dao
|
2
|
+
module Middleware
|
3
|
+
class ParamsParser
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
@env = env
|
10
|
+
#if params = parse_formatted_parameters(env)
|
11
|
+
#env["action_dispatch.request.request_parameters"] = params
|
12
|
+
#end
|
13
|
+
|
14
|
+
query_parameters = @env["action_controller.request.query_parameters"]
|
15
|
+
request_parameters = @env["action_controller.request.request_parameters"]
|
16
|
+
|
17
|
+
Rails.logger.info("query_parameters : #{ query_parameters.inspect }")
|
18
|
+
Rails.logger.info("request_parameters : #{ request_parameters.inspect }")
|
19
|
+
|
20
|
+
@app.call(@env)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/dao/rails.rb
CHANGED
@@ -17,26 +17,43 @@ if defined?(Rails)
|
|
17
17
|
|
18
18
|
paths.path = ROOT_DIR
|
19
19
|
|
20
|
+
config.autoload_paths += %w( app/models app )
|
21
|
+
|
20
22
|
### config.autoload_paths << APP_DIR
|
21
23
|
### $LOAD_PATH.push(File.join(Rails.root.to_s, 'app'))
|
22
24
|
|
25
|
+
# drop the dao parameter parser in there...
|
26
|
+
#
|
27
|
+
#initializer "dao.middleware" do |app|
|
28
|
+
#app.middleware.use Dao::Middleware::ParamsParser
|
29
|
+
#end
|
30
|
+
|
23
31
|
# yes yes, this should probably be somewhere else...
|
24
32
|
#
|
25
33
|
config.after_initialize do
|
26
34
|
|
27
35
|
ActionController::Base.module_eval do
|
28
36
|
|
37
|
+
before_filter do |controller|
|
38
|
+
# set the dao controller
|
39
|
+
#
|
40
|
+
Dao.current_controller = controller
|
41
|
+
|
42
|
+
# pre-parse any obvious dao params
|
43
|
+
#
|
44
|
+
controller.instance_eval do
|
45
|
+
Dao.normalize_parameters(params)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
29
49
|
# you will likely want to override this!
|
30
50
|
#
|
31
51
|
def current_api
|
32
52
|
@api ||= (
|
33
53
|
api = Api.new
|
34
54
|
%w( real_user effective_user current_user ).each do |attr|
|
35
|
-
getter = "#{ attr }"
|
36
|
-
setter
|
37
|
-
if respond_to?(getter) and api.respond_to?(setter)
|
38
|
-
api.send(setter, send(getter))
|
39
|
-
end
|
55
|
+
getter, setter = "#{ attr }", "#{ attr }="
|
56
|
+
api.send(setter, send(getter)) if(respond_to?(getter) and api.respond_to?(setter))
|
40
57
|
end
|
41
58
|
api
|
42
59
|
)
|
@@ -1,15 +1,60 @@
|
|
1
1
|
class DaoGenerator < Rails::Generators::NamedBase
|
2
|
-
source_root
|
2
|
+
source_root(File.expand_path('../templates', __FILE__))
|
3
3
|
|
4
|
-
def
|
5
|
-
|
4
|
+
def copy_files
|
5
|
+
ARGV.shift if ARGV.first == name
|
6
6
|
|
7
|
-
|
7
|
+
case name
|
8
|
+
when /conducer_controller/
|
9
|
+
generate_conducer_controller!
|
10
|
+
|
11
|
+
when /conducer/
|
12
|
+
generate_conducer!
|
13
|
+
|
14
|
+
when /system/
|
15
|
+
generate_system!
|
16
|
+
|
17
|
+
when /api/
|
18
|
+
generate_system!
|
19
|
+
|
20
|
+
when /conducers/
|
21
|
+
generate_system!
|
22
|
+
|
23
|
+
when /assets/
|
24
|
+
generate_system!
|
8
25
|
|
26
|
+
else
|
27
|
+
raise "dunno how to generate #{ name.inspect }"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
def generate_conducer_controller!
|
33
|
+
@conducer_name = ARGV.shift.sub(/_?conducer$/i, '') + '_conducer'
|
34
|
+
@controller_name = @conducer_name.sub(/_conducer/, '_controller')
|
35
|
+
|
36
|
+
template "conducer_controller.rb", "app/controllers/#{ @conducer_name.underscore }.rb"
|
37
|
+
#template "conducer.rb", "app/conducers/#{ @conducer_name.underscore }.rb"
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_conducer!
|
41
|
+
@conducer_name = ARGV.shift.sub(/_?conducer$/i, '') + '_conducer'
|
42
|
+
template "conducer.rb", "app/conducers/#{ @conducer_name.underscore }.rb"
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_system!
|
46
|
+
dao_dir = File.join(Rails.root, 'app/dao')
|
47
|
+
|
48
|
+
FileUtils.mkdir_p(dao_dir)
|
49
|
+
FileUtils.mkdir_p(File.join(dao_dir, 'apis'))
|
50
|
+
FileUtils.mkdir_p(File.join(dao_dir, 'conducers'))
|
51
|
+
|
52
|
+
copy_file("api.rb", "app/dao/api.rb")
|
53
|
+
|
54
|
+
copy_file("api_controller.rb", "app/controllers/api_controller.rb")
|
9
55
|
copy_file("dao_helper.rb", "app/helpers/dao_helper.rb")
|
10
56
|
|
11
57
|
copy_file("dao.js", "public/javascripts/dao.js")
|
12
|
-
|
13
58
|
copy_file("dao.css", "public/stylesheets/dao.css")
|
14
59
|
|
15
60
|
route("match 'api(/*path)' => 'api#index', :as => 'api'")
|
@@ -20,11 +65,11 @@ class DaoGenerator < Rails::Generators::NamedBase
|
|
20
65
|
<<-__
|
21
66
|
|
22
67
|
config.after_initialize do
|
23
|
-
require 'app/api.rb'
|
68
|
+
require 'app/dao/api.rb'
|
24
69
|
require 'yajl/json_gem'
|
25
70
|
end
|
26
71
|
|
27
|
-
config.autoload_paths += %w( app )
|
72
|
+
config.autoload_paths += %w( app/models app/dao app/dao/apis app/dao/conducers )
|
28
73
|
|
29
74
|
### config.action_view.javascript_expansions[:defaults] ||= []
|
30
75
|
### config.action_view.javascript_expansions[:defaults] += %( dao )
|
@@ -12,12 +12,12 @@ Api =
|
|
12
12
|
|
13
13
|
##
|
14
14
|
#
|
15
|
-
|
15
|
+
desc '/ping - hello world without a user'
|
16
16
|
call('/ping'){
|
17
17
|
data.update :time => Time.now
|
18
18
|
}
|
19
19
|
|
20
|
-
|
20
|
+
desc '/pong - hello world with a user'
|
21
21
|
call('/pong'){
|
22
22
|
require_current_user!
|
23
23
|
data.update :time => Time.now
|
@@ -48,6 +48,8 @@ Api =
|
|
48
48
|
alias_method('user=', 'effective_user=')
|
49
49
|
alias_method('current_user', 'effective_user')
|
50
50
|
alias_method('current_user=', 'effective_user=')
|
51
|
+
alias_method('effective_user?', 'effective_user')
|
52
|
+
alias_method('real_user?', 'real_user')
|
51
53
|
|
52
54
|
def api
|
53
55
|
self
|
@@ -77,7 +79,7 @@ Api =
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def require_real_user!
|
80
|
-
unless
|
82
|
+
unless real_user?
|
81
83
|
status :unauthorized
|
82
84
|
return!
|
83
85
|
end
|
@@ -89,9 +91,23 @@ Api =
|
|
89
91
|
alias_method('require_user!', 'require_current_user!')
|
90
92
|
end
|
91
93
|
|
94
|
+
## look for any other apis to load
|
95
|
+
#
|
96
|
+
%w( api apis ).each do |dir|
|
97
|
+
glob = File.expand_path(File.join(Rails.root, "app/#{ dir }/**/*.rb"))
|
98
|
+
files = Dir.glob(glob).sort
|
99
|
+
files.each{|file| ::Kernel.load(file)}
|
100
|
+
end
|
92
101
|
|
93
|
-
|
102
|
+
## mo betta in development
|
103
|
+
#
|
104
|
+
unloadable(Api)
|
94
105
|
|
95
|
-
|
96
|
-
|
97
|
-
|
106
|
+
## top level method shortcut
|
107
|
+
#
|
108
|
+
module Kernel
|
109
|
+
protected
|
110
|
+
def api(*args, &block)
|
111
|
+
Api.new(*args, &block)
|
112
|
+
end
|
113
|
+
end
|
@@ -3,8 +3,9 @@ class APIController < ApplicationController
|
|
3
3
|
|
4
4
|
skip_before_filter :verify_authenticity_token
|
5
5
|
|
6
|
-
before_filter :setup_path
|
7
6
|
before_filter :setup_api
|
7
|
+
before_filter :setup_mode
|
8
|
+
before_filter :setup_path
|
8
9
|
|
9
10
|
WhiteList = Set.new( %w( ping index ) )
|
10
11
|
BlackList = Set.new( %w( ) )
|
@@ -17,8 +18,7 @@ class APIController < ApplicationController
|
|
17
18
|
protected
|
18
19
|
|
19
20
|
def call(path, params)
|
20
|
-
|
21
|
-
result = api.mode(mode).call(path, params)
|
21
|
+
@result = api.mode(@mode).call(path, params)
|
22
22
|
end
|
23
23
|
|
24
24
|
def respond_with(object, options = {})
|
@@ -30,25 +30,42 @@ protected
|
|
30
30
|
respond_to do |wants|
|
31
31
|
wants.json{ render :json => json, :status => status }
|
32
32
|
wants.html{ render :text => json, :status => status, :content_type => 'text/plain' }
|
33
|
+
wants.xml{ render :text => 'no soup for you!', :status => 403 }
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
37
|
def json_for(object)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
begin
|
39
|
+
if Rails.env.production?
|
40
|
+
::JSON.generate(object)
|
41
|
+
else
|
42
|
+
::JSON.pretty_generate(object, :max_nesting => 0)
|
43
|
+
end
|
44
|
+
rescue Object => e
|
45
|
+
Rails.logger.error(e)
|
46
|
+
YAML.load( object.to_yaml ).to_json
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
44
50
|
def setup_path
|
45
51
|
@path = params[:path] || params[:action] || 'index'
|
52
|
+
unless api.route?(@path) or @path=='index'
|
53
|
+
render :nothing => true, :status => 404
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def setup_mode
|
58
|
+
@mode = params['mode'] || (request.get? ? 'read' : 'write')
|
46
59
|
end
|
47
60
|
|
48
61
|
def path
|
49
62
|
@path
|
50
63
|
end
|
51
64
|
|
65
|
+
def mode
|
66
|
+
@mode
|
67
|
+
end
|
68
|
+
|
52
69
|
##
|
53
70
|
# you'll likely want to customize this for you app as it makes a few
|
54
71
|
# assumptions about how to find and authenticate users
|
@@ -0,0 +1,64 @@
|
|
1
|
+
<%
|
2
|
+
|
3
|
+
class_name = @conducer_name.camelize
|
4
|
+
model_name = class_name.sub(/Conducer/, '')
|
5
|
+
|
6
|
+
-%>
|
7
|
+
class <%= class_name %> < Dao::Conducer
|
8
|
+
## class_methods
|
9
|
+
#
|
10
|
+
class << <%= class_name %>
|
11
|
+
def all(params = {})
|
12
|
+
records = <%= model_name %>.paginate(params)
|
13
|
+
|
14
|
+
records.map! do |record|
|
15
|
+
new(record.attributes)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def find(id)
|
20
|
+
raise NotImplementedError, <<-__
|
21
|
+
this needs to return an instance based on the id
|
22
|
+
__
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
## instance_methods
|
27
|
+
#
|
28
|
+
def initialize
|
29
|
+
run_callbacks :initialize do
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def save
|
34
|
+
run_callbacks :save do
|
35
|
+
return(false) unless valid?
|
36
|
+
|
37
|
+
raise NotImplementedError, <<-__
|
38
|
+
this needs to
|
39
|
+
- persist data to the db and get a new id
|
40
|
+
- set the id on the object : @attributes.set(:id => id)
|
41
|
+
- return true or false
|
42
|
+
__
|
43
|
+
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def destroy
|
49
|
+
run_callbacks :destroy do
|
50
|
+
id = self.id
|
51
|
+
if id
|
52
|
+
|
53
|
+
raise NotImplementedError, <<-__
|
54
|
+
this needs to
|
55
|
+
- un-persist data from the db
|
56
|
+
- set the id on the object to nil : @attributes.rm(:id)
|
57
|
+
- return this id of the destroyed object
|
58
|
+
__
|
59
|
+
|
60
|
+
end
|
61
|
+
id
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|