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.
Files changed (60) hide show
  1. data/README +7 -0
  2. data/Rakefile +36 -17
  3. data/b.rb +38 -0
  4. data/dao.gemspec +41 -13
  5. data/lib/dao.rb +44 -13
  6. data/lib/dao/api.rb +1 -1
  7. data/lib/dao/api/context.rb +35 -45
  8. data/lib/dao/api/endpoints.rb +225 -91
  9. data/lib/dao/conducer.rb +437 -0
  10. data/lib/dao/conducer/attributes.rb +21 -0
  11. data/lib/dao/conducer/crud.rb +70 -0
  12. data/lib/dao/current.rb +66 -0
  13. data/lib/dao/db.rb +44 -5
  14. data/lib/dao/endpoint.rb +13 -1
  15. data/lib/dao/errors.rb +74 -59
  16. data/lib/dao/exceptions.rb +1 -2
  17. data/lib/dao/extractor.rb +68 -0
  18. data/lib/dao/form.rb +139 -46
  19. data/lib/dao/image_cache.rb +193 -0
  20. data/lib/dao/instance_exec.rb +1 -1
  21. data/lib/dao/name.rb +7 -0
  22. data/lib/dao/params.rb +16 -66
  23. data/lib/dao/rack.rb +3 -0
  24. data/lib/dao/rack/middleware.rb +5 -0
  25. data/lib/dao/rack/middleware/params_parser.rb +24 -0
  26. data/lib/dao/rails.rb +22 -5
  27. data/lib/dao/rails/lib/generators/dao/USAGE +2 -6
  28. data/lib/dao/rails/lib/generators/dao/dao_generator.rb +52 -7
  29. data/lib/dao/rails/lib/generators/dao/templates/api.rb +23 -7
  30. data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +24 -7
  31. data/lib/dao/rails/lib/generators/dao/templates/conducer.rb +64 -0
  32. data/lib/dao/rails/lib/generators/dao/templates/conducer_controller.rb +79 -0
  33. data/lib/dao/rails/lib/generators/dao/templates/dao.js +13 -6
  34. data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +75 -11
  35. data/lib/dao/result.rb +1 -26
  36. data/lib/dao/slug.rb +37 -8
  37. data/lib/dao/status.rb +4 -0
  38. data/lib/dao/support.rb +155 -0
  39. data/lib/dao/validations.rb +48 -157
  40. data/lib/dao/validations/callback.rb +30 -0
  41. data/lib/dao/validations/common.rb +322 -320
  42. data/lib/dao/validations/validator.rb +219 -0
  43. data/test/active_model_conducer_lint_test.rb +19 -0
  44. data/test/api_test.rb +261 -0
  45. data/test/conducer_test.rb +205 -0
  46. data/test/db.yml +9 -0
  47. data/test/form_test.rb +42 -0
  48. data/test/support_test.rb +52 -0
  49. data/test/testing.rb +145 -24
  50. data/test/validations_test.rb +156 -0
  51. metadata +138 -21
  52. data/TODO +0 -33
  53. data/a.rb +0 -80
  54. data/db/dao.yml +0 -5
  55. data/lib/dao/api/interfaces.rb +0 -306
  56. data/lib/dao/interface.rb +0 -28
  57. data/lib/dao/presenter.rb +0 -129
  58. data/lib/dao/rails/lib/generators/dao/api_generator.rb +0 -3
  59. data/lib/dao/validations/base.rb +0 -68
  60. data/test/dao_test.rb +0 -506
@@ -1,6 +1,6 @@
1
1
  module Dao
2
2
  module InstanceExec
3
- Code = lambda do
3
+ Code = proc do
4
4
  unless Object.new.respond_to?(:instance_exec)
5
5
  module InstanceExecHelper; end
6
6
  include InstanceExecHelper
data/lib/dao/name.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Dao
2
+ class Name < ::String
3
+ def Name.for(name)
4
+ name.is_a?(Name) ? name : Name.new(name)
5
+ end
6
+ end
7
+ end
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::Mixin
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 :status
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
- @path = Path.default
79
- @status = Status.default
80
- @errors = Errors.new
81
- @validations = Validations.for(self)
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,3 @@
1
+ if defined?(Rack)
2
+ Dao.load %w[ rack/middleware.rb ]
3
+ end
@@ -0,0 +1,5 @@
1
+ module Dao
2
+ module Middleware
3
+ Dao.load %w[ rack/middleware/params_parser.rb ]
4
+ end
5
+ end
@@ -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 = "#{ attr }="
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,9 +1,5 @@
1
1
  Description:
2
- rails generate dao api
3
- rails generate dao api controller
4
- rails generate dao paths
2
+ rails generate dao system
5
3
 
6
4
  Example:
7
- rails generate dao api
8
- rails generate dao api controller
9
- rails generate dao paths
5
+ rails generate dao system
@@ -1,15 +1,60 @@
1
1
  class DaoGenerator < Rails::Generators::NamedBase
2
- source_root File.expand_path('../templates', __FILE__)
2
+ source_root(File.expand_path('../templates', __FILE__))
3
3
 
4
- def copy_api_file
5
- copy_file("api.rb", "app/api.rb")
4
+ def copy_files
5
+ ARGV.shift if ARGV.first == name
6
6
 
7
- copy_file("api_controller.rb", "app/controllers/api_controller.rb")
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
- doc '/ping - hello world without a user'
15
+ desc '/ping - hello world without a user'
16
16
  call('/ping'){
17
17
  data.update :time => Time.now
18
18
  }
19
19
 
20
- doc '/pong - hello world with a user'
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 effective_user?
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
- unloadable(Api)
102
+ ## mo betta in development
103
+ #
104
+ unloadable(Api)
94
105
 
95
- def api(*args, &block)
96
- Api.new(*args, &block)
97
- end
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
- mode = params['mode'] || (request.get? ? 'read' : 'write')
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
- if Rails.env.production?
38
- ::JSON.generate(object)
39
- else
40
- ::JSON.pretty_generate(object, :max_nesting => 0)
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