dao 2.0.0 → 2.1.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.
@@ -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
+ }