dao 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,37 @@
1
+ module Dao
2
+ module InstanceExec
3
+ Code = lambda do
4
+ unless Object.new.respond_to?(:instance_exec)
5
+ module InstanceExecHelper; end
6
+ include InstanceExecHelper
7
+
8
+ def instance_exec(*args, &block)
9
+ begin
10
+ old_critical, Thread.critical = Thread.critical, true
11
+ n = 0
12
+ n += 1 while respond_to?(mname="__instance_exec_#{ n }__")
13
+ InstanceExecHelper.module_eval{ define_method(mname, &block) }
14
+ ensure
15
+ Thread.critical = old_critical
16
+ end
17
+ begin
18
+ ret = send(mname, *args)
19
+ ensure
20
+ InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
21
+ end
22
+ ret
23
+ end
24
+ end
25
+ end
26
+
27
+ def InstanceExec.included(other)
28
+ other.module_eval(&Code)
29
+ super
30
+ end
31
+
32
+ def InstanceExec.extend_object(other)
33
+ other.instance_eval(&Code)
34
+ super
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ module Dao
2
+ class Interface
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/params.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Dao
2
2
  class Params < ::Map
3
+ include Dao::InstanceExec
4
+
3
5
  class << Params
4
6
  def parse(prefix, params = {})
5
7
  prefix = prefix.to_s
@@ -24,7 +26,7 @@ module Dao
24
26
  end
25
27
 
26
28
  attr_accessor :api
27
- attr_accessor :endpoint
29
+ attr_accessor :interface
28
30
  attr_accessor :params
29
31
  attr_accessor :result
30
32
 
@@ -32,12 +34,12 @@ module Dao
32
34
  options = Dao.options_for!(args)
33
35
 
34
36
  api = options[:api]
35
- endpoint = options[:endpoint]
37
+ interface = options[:interface]
36
38
  updates = options[:params]
37
39
 
38
40
  params = new()
39
41
  params.api = api
40
- params.endpoint = endpoint
42
+ params.interface = interface
41
43
 
42
44
  params.update(updates) if updates
43
45
 
@@ -78,32 +80,54 @@ module Dao
78
80
  def validate!
79
81
  result.validate! if result
80
82
  end
83
+ end
81
84
 
82
- unless Object.new.respond_to?(:instance_exec)
83
- module InstanceExecHelper; end
84
- include InstanceExecHelper
85
-
86
- def instance_exec(*args, &block)
87
- begin
88
- old_critical, Thread.critical = Thread.critical, true
89
- n = 0
90
- n += 1 while respond_to?(mname="__instance_exec_#{ n }__")
91
- InstanceExecHelper.module_eval{ define_method(mname, &block) }
92
- ensure
93
- Thread.critical = old_critical
94
- end
95
- begin
96
- ret = send(mname, *args)
97
- ensure
98
- InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
99
- end
100
- ret
85
+ def Dao.parse(path, params)
86
+ return params if params.is_a?(Params)
87
+
88
+ smells_like_unparsed_rails_params = (
89
+ params.has_key?(:action) and
90
+ params.has_key?(:controller) and
91
+ params.class.name =~ /HashWithIndifferentAccess/
92
+ )
93
+ return(Params.parse(path.to_s, params)) if smells_like_unparsed_rails_params
94
+
95
+ smells_like_unparsed_params = false
96
+ unparsed_re = %r/^#{ Regexp.escape(path.to_s) }/
97
+ params.each do |key, val|
98
+ if key =~ unparsed_re
99
+ smells_like_unparsed_params = true
100
+ break
101
101
  end
102
102
  end
103
+ return(Params.parse(path.to_s, params)) if smells_like_unparsed_params
104
+
105
+ return Params.new(params)
103
106
  end
104
107
 
108
+ =begin
109
+ def Dao.parse(path, params)
110
+ returned = Params.new(params)
111
+
112
+ smells_like_rails = (params.has_key?(:action) and params.has_key?(:controller) and params.class.name =~ /HashWithIndifferentAccess/)
113
+ if smells_like_rails
114
+ returned.delete(:action)
115
+ returned.delete(:controller)
116
+ returned.update(Params.parse(path, params))
117
+ return returned
118
+ end
119
+
120
+ re = %r/^#{ Regexp.escape(path) }/
121
+ smells_like_unparsed = false
122
+ params.each do |key, val|
123
+ break(smells_like_unparsed = true) if key =~ re
124
+ end
125
+ if smells_like_unparsed
126
+ returned.update(Params.parse(path, params))
127
+ return returned
128
+ end
105
129
 
106
- def Dao.parse(*args, &block)
107
- Params.parse(*args, &block)
130
+ return returned
108
131
  end
132
+ =end
109
133
  end
data/lib/dao/path.rb CHANGED
@@ -78,7 +78,7 @@ module Dao
78
78
  attr_accessor :keys
79
79
  attr_accessor :pattern
80
80
  attr_accessor :params
81
- attr_accessor :endpoint
81
+ attr_accessor :interface
82
82
 
83
83
  def initialize(*args, &block)
84
84
  super(args.join('/'), &block)
data/lib/dao/rails.rb CHANGED
@@ -3,13 +3,16 @@ if defined?(Rails)
3
3
  class Engine < Rails::Engine
4
4
  GEM_DIR = File.expand_path(__FILE__ + '/../../../')
5
5
  ROOT_DIR = File.join(GEM_DIR, 'lib/dao/rails')
6
- #APP_DIR = File.join(ROOT_DIR, 'app')
7
6
 
8
- ### https://gist.github.com/af7e572c2dc973add221
7
+ ### ref: https://gist.github.com/af7e572c2dc973add221
9
8
 
10
9
  paths.path = ROOT_DIR
11
10
  ### config.autoload_paths << APP_DIR
12
11
  ### $LOAD_PATH.push(File.join(Rails.root.to_s, 'app'))
12
+
13
+ #config.after_initialize do
14
+ #unloadable(Dao)
15
+ #end
13
16
  end
14
17
  end
15
18
  end
@@ -2,7 +2,7 @@ Api =
2
2
  Dao.api do
3
3
 
4
4
  description 'ping!'
5
- endpoint('/ping'){
5
+ interface('/ping'){
6
6
  data.update :time => Time.now
7
7
  }
8
8
 
@@ -6,6 +6,12 @@ class DaoGenerator < Rails::Generators::NamedBase
6
6
 
7
7
  copy_file("api_controller.rb", "app/controllers/api_controller.rb")
8
8
 
9
+ copy_file("dao_helper.rb", "app/helpers/dao_helper.rb")
10
+
11
+ copy_file("dao.js", "public/javascripts/dao.js")
12
+
13
+ copy_file("dao.css", "public/stylesheets/dao.css")
14
+
9
15
  route("match 'api/*path' => 'api#call', :as => 'api'")
10
16
  route("match 'api' => 'api#index', :as => 'api_index'")
11
17
 
@@ -21,6 +27,12 @@ class DaoGenerator < Rails::Generators::NamedBase
21
27
 
22
28
  config.autoload_paths += %w( app )
23
29
 
30
+ ### config.action_view.javascript_expansions[:defaults] ||= []
31
+ ### config.action_view.javascript_expansions[:defaults] += %( dao )
32
+
33
+ ### config.action_view.stylesheet_expansions[:defaults] ||= []
34
+ ### config.action_view.stylesheet_expansions[:defaults] += %( dao )
35
+
24
36
  __
25
37
  )
26
38
  end
@@ -2,7 +2,7 @@ Api =
2
2
  Dao.api do
3
3
 
4
4
  description 'ping!'
5
- endpoint('/ping'){
5
+ interface('/ping'){
6
6
  data.update :time => Time.now
7
7
  }
8
8
 
@@ -29,6 +29,8 @@ Api =
29
29
 
30
30
  alias_method('user', 'effective_user')
31
31
  alias_method('user=', 'effective_user=')
32
+ alias_method('current_user', 'effective_user')
33
+ alias_method('current_user=', 'effective_user=')
32
34
 
33
35
  def api
34
36
  self
@@ -53,3 +55,7 @@ Api =
53
55
 
54
56
 
55
57
  unloadable(Api)
58
+
59
+ def api(*args, &block)
60
+ Api.new(*args, &block)
61
+ end
@@ -4,8 +4,11 @@ class APIController < ApplicationController
4
4
  skip_before_filter true
5
5
  skip_before_filter :verify_authenticity_token
6
6
 
7
+ before_filter :setup_path
7
8
  before_filter :setup_api
8
9
 
10
+ WhiteList = %w( ping index module )
11
+
9
12
  ### skip_before_filter :set_current_user if Rails.env.production?
10
13
 
11
14
  ##
@@ -52,7 +55,20 @@ protected
52
55
  end
53
56
  end
54
57
 
58
+ def setup_path
59
+ @path = params[:path]
60
+ end
61
+
62
+ def path
63
+ @path
64
+ end
65
+
55
66
  def setup_api
67
+ if white_listed?(path)
68
+ @api = Api.new
69
+ return
70
+ end
71
+
56
72
  email, password = http_basic_auth_info
57
73
 
58
74
  if !email.blank? and !password.blank?
@@ -80,6 +96,15 @@ protected
80
96
  @api
81
97
  end
82
98
 
99
+ def self.white_listed?(path)
100
+ @white_listed ||= ( WhiteList.inject(Hash.new){|hash, path| hash.update(path.to_s => true)} )
101
+ @white_listed[path.to_s]
102
+ end
103
+
104
+ def white_listed?(path)
105
+ self.class.white_listed?(path)
106
+ end
107
+
83
108
  def http_basic_auth
84
109
  @http_basic_auth ||= (
85
110
  request.env['HTTP_AUTHORIZATION'] ||
@@ -0,0 +1,27 @@
1
+ /* dao errors */
2
+ table.dao.errors {
3
+ font-weight: normal;
4
+ width: 100%;
5
+ border-bottom: 1px solid #ccc;
6
+ }
7
+ table.dao.errors caption {
8
+ font-weight: bold;
9
+ color: #333;
10
+ font-style: italic;
11
+ text-align: left;
12
+ margin-bottom: 0.5em;
13
+ }
14
+ table.dao.errors td.key {
15
+ padding-left: 1em;
16
+ color: #666;
17
+ }
18
+ table.dao.errors td.separator {
19
+ color: #666;
20
+ padding-left: 0.5em;
21
+ padding-right: 0.5em;
22
+ }
23
+ table.dao.errors td.message {
24
+ font-style: italic;
25
+ width: 100%;
26
+ }
27
+
@@ -0,0 +1,149 @@
1
+ if(!window.Dao){
2
+ (function(){
3
+ window.Dao = {};
4
+
5
+ // pull jQuery off the CDN iff needed
6
+ //
7
+ !window.jQuery && document.write(unescape('%3Cscript src="js/libs/jquery-1.4.2.js"%3E%3C/script%3E'));
8
+ var jq = jQuery;
9
+
10
+ // ctor
11
+ //
12
+ Dao.Api = function(){
13
+ this.route = '' + Dao.Api.route;
14
+ this.result = null;
15
+ this.results = [];
16
+ this.mode = 'get';
17
+ this.method = Dao[this.mode];
18
+ };
19
+ Dao.Api.route = '/api';
20
+ Dao.Api.modes = ["options", "get", "head", "post", "put", "delete", "trace", "connect"];
21
+
22
+ // single call interface
23
+ //
24
+ Dao.Api.prototype.call = function(){
25
+ var api = this;
26
+ var options = {};
27
+
28
+ if(arguments.length == 1){
29
+ var arg = arguments[0];
30
+
31
+ if(typeof(arg)=='string'){
32
+ options.path = arg;
33
+ } else {
34
+ options = arg;
35
+ }
36
+ }
37
+
38
+ if(arguments.length > 1){
39
+ options.path = arguments[0];
40
+ options.params = arguments[1];
41
+ options.success = arguments[2];
42
+ }
43
+
44
+ if(!options.path){
45
+ options.path = '/ping';
46
+ }
47
+
48
+ if(!options.params){
49
+ options.params = {};
50
+ }
51
+
52
+ if(!options.success){
53
+ options.success = function(result){
54
+ result = new Dao.Result(result);
55
+ api.result = result;
56
+ api.results.push(result);
57
+ };
58
+ }
59
+
60
+ var url = api.route + options.path;
61
+
62
+ var data = options.params;
63
+
64
+ var success = function(result){
65
+ var result = new Dao.Result(result);
66
+ if(options.success){
67
+ options.success(result);
68
+ } else {
69
+ api.result = result;
70
+ api.results.push(result);
71
+ }
72
+ };
73
+
74
+ var ajax = {};
75
+ ajax.url = url;
76
+ ajax.data = data;
77
+ ajax.success = success;
78
+
79
+ Dao[api.mode](ajax);
80
+ return(api);
81
+ };
82
+
83
+ // meta-program api.read(..), api.post(...), ...
84
+ //
85
+ for(var i = 0; i < Dao.Api.modes.length; i++){
86
+ (function(){
87
+ var mode = Dao.Api.modes[i];
88
+
89
+ Dao.Api.prototype[mode] = function(){
90
+ var api = this;
91
+ var previous = api.mode;
92
+ api.mode = mode;
93
+ var returned = api.call.apply(api, arguments);
94
+ api.mode = previous;
95
+ return(returned);
96
+ };
97
+ })();
98
+ }
99
+ Dao.Api.prototype['read'] = Dao.Api.prototype['get'];
100
+ Dao.Api.prototype['write'] = Dao.Api.prototype['post'];
101
+
102
+ // a thin wrapper on results for now. TODO - make it smarter
103
+ //
104
+ Dao.Result = function(options){
105
+ this.path = options.path;
106
+ this.status = options.status;
107
+ this.errors = options.errors;
108
+ this.data = options.data;
109
+
110
+ //parts = ('' + this.status).split(/\s+/);
111
+ //this.status.code = parseInt(parts.shift());
112
+ //this.status.message = parts.join(' ');
113
+ };
114
+
115
+ // ajax utils
116
+ //
117
+ Dao.ajax = function(options){
118
+ var ajax = {};
119
+ ajax.type = options.type;
120
+ ajax.url = options.url;
121
+ ajax.dataType = 'json';
122
+ ajax.cache = false;
123
+ if(ajax.type == 'POST' || ajax.type == 'PUT'){
124
+ ajax.data = jq.toJSON(options.data || {});
125
+ } else {
126
+ ajax.data = (options.data || {});
127
+ };
128
+ ajax.contentType = (options.contentType || 'application/json; charset=utf-8');
129
+ ajax.success = (options.success || function(){});
130
+ jq.ajax(ajax);
131
+ };
132
+
133
+ // meta-program Api.get(...), Api.post(...)
134
+ //
135
+ for(var i = 0; i < Dao.Api.modes.length; i++){
136
+ (function(){
137
+ var mode = Dao.Api.modes[i];
138
+
139
+ Dao[mode] = function(options){
140
+ options.type = mode.toUpperCase();
141
+ Dao.ajax(options);
142
+ };
143
+ })();
144
+ }
145
+
146
+ Dao.api = new Dao.Api();
147
+ window.api = window.api || Dao.api;
148
+ }());
149
+ }