droid_services 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Droidlabs
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # DroidServices
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'droid_services'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install droid_services
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,11 @@
1
+ class DroidServices::Base
2
+ include DroidServices::Extensions::HasLogger
3
+ include DroidServices::Extensions::HasResponse
4
+
5
+ attr_accessor :params, :accessor
6
+
7
+ def initialize(options = {})
8
+ @accessor = options[:as]
9
+ @params = options[:params]
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ class DroidServices::BaseResource < DroidServices::Base
2
+ include DroidServices::Extensions::HasResource
3
+ include DroidServices::Extensions::HasCallbacks
4
+ include DroidServices::Extensions::HasService
5
+ include DroidServices::Extensions::HasDecorator
6
+ end
@@ -0,0 +1,17 @@
1
+ class DroidServices::Callbacks
2
+ attr_accessor :resource
3
+
4
+ def initialize(resource)
5
+ @resource = resource
6
+ end
7
+
8
+ def before_save; end
9
+ def before_create; end
10
+ def before_update; end
11
+ def before_destroy; end
12
+
13
+ def after_save; end
14
+ def after_create; end
15
+ def after_update; end
16
+ def after_destroy; end
17
+ end
@@ -0,0 +1,13 @@
1
+ class DroidServices::Decorator
2
+ attr_accessor :resource
3
+
4
+ def initialize(resource)
5
+ @resource = resource
6
+ end
7
+
8
+ def method_missing(method, *args, &block)
9
+ return super unless resource.respond_to?(method)
10
+
11
+ resource.send(method, *args, &block)
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_support/core_ext/object'
2
+ require 'active_support/core_ext/class'
3
+
4
+ module DroidServices::Extensions
5
+ module HasCallbacks
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :resource_callbacks_handler_class
10
+ end
11
+
12
+ def invoke_callback(name, resource)
13
+ if resource_callbacks_handler_class
14
+ resource_callbacks_handler_class.new(resource).send(name)
15
+ end
16
+ end
17
+
18
+ module ClassMethods
19
+ def callbacks_handler(name, options = {})
20
+ self.resource_callbacks_handler_class = name
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,49 @@
1
+ module DroidServices::Extensions
2
+ module HasDecorator
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :decorator_class_name
7
+ end
8
+
9
+ module ClassMethods
10
+ def decorator(name)
11
+ self.decorator_class_name = name.to_s
12
+ end
13
+ end
14
+
15
+ def decorated_collection
16
+ if decorable?
17
+ build_decorated_collection
18
+ else
19
+ build_collection
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def decorable?
26
+ !self.class.decorator_class_name.nil?
27
+ end
28
+
29
+ def decorator_class
30
+ self.class.decorator_class_name.to_s.classify.constantize
31
+ end
32
+
33
+ def prepare_collection_for_decorate
34
+ collection = build_collection
35
+
36
+ if collection.kind_of?(Array)
37
+ return collection
38
+ elsif collection.respond_to?(:all)
39
+ return collection.all
40
+ else
41
+ return Array.wrap(collection)
42
+ end
43
+ end
44
+
45
+ def build_decorated_collection
46
+ prepare_collection_for_decorate.map{|i| decorator_class.new(i)}
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ require 'yell'
2
+ require 'active_support'
3
+ require 'active_support/core_ext/kernel/reporting'
4
+ require 'active_support/inflector'
5
+ require 'json'
6
+
7
+ module DroidServices::Extensions
8
+ module HasLogger
9
+ extend ActiveSupport::Concern
10
+
11
+ silence_warnings do
12
+ Yell::Formatter::PatternRegexp = /([^%]*)(%\d*)?(#{Yell::Formatter::PatternTable.keys.join('|')})?(.*)/m
13
+ end
14
+
15
+ included do
16
+ class << self
17
+ def logger
18
+ @logger ||= Yell.new do |l|
19
+ l.adapter :datefile, log_file,
20
+ level: (:debug..:fatal),
21
+ format: Yell.format( "%d [%5L] #%M at %F:%n\n%m\n\n", "%H:%M:%S" ),
22
+ date_pattern: "%Y-week-%V",
23
+ symlink_original_filename: true,
24
+ keep: 4
25
+ end
26
+ end
27
+
28
+ def format_message(message)
29
+ case message
30
+ when String
31
+ message
32
+ when Hash, Array
33
+ JSON::pretty_generate message
34
+ else message.inspect
35
+ end
36
+ end
37
+
38
+ private
39
+ def log_file
40
+ path = File.join(rails_log_path, "#{self.name.underscore}.log")
41
+ FileUtils.mkdir_p File.dirname(path)
42
+ path.to_s
43
+ end
44
+
45
+ def rails_log_path
46
+ File.join(Rails.root, 'log', Rails.env)
47
+ end
48
+ end
49
+
50
+ def logger
51
+ self.class.logger
52
+ end
53
+
54
+ def format_message(message)
55
+ self.class.format_message(message)
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,68 @@
1
+ module DroidServices::Extensions
2
+ module HasResource
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :resource_name
7
+ class_attribute :resource_class_name
8
+ end
9
+
10
+ def resource_class
11
+ if self.class.resource_class_name
12
+ self.class.resource_class_name.constantize
13
+ else
14
+ resource_name.classify.constantize
15
+ end
16
+ end
17
+
18
+ def resource_scope
19
+ resource_class
20
+ end
21
+
22
+ def collection_name
23
+ resource_name.pluralize
24
+ end
25
+
26
+ def resource_attributes
27
+ filter_attributes(dirty_resource_attributes)
28
+ end
29
+
30
+ def build_resource(id, attributes = {})
31
+ if id.present?
32
+ resource = find_resource(id)
33
+ resource.attributes = attributes
34
+ resource
35
+ else
36
+ resource_scope.new(default_resource_attributes.merge(attributes))
37
+ end
38
+ end
39
+
40
+ def build_collection
41
+ resource_scope
42
+ end
43
+
44
+ def find_resource(id)
45
+ resource_scope.find(id)
46
+ end
47
+
48
+ module ClassMethods
49
+ def resource(name, options = {})
50
+ self.resource_name = name.to_s
51
+ self.resource_class_name = options[:class_name]
52
+ end
53
+ end
54
+
55
+ private
56
+ def dirty_resource_attributes
57
+ params[resource_name] || {}
58
+ end
59
+
60
+ def default_resource_attributes
61
+ {}
62
+ end
63
+
64
+ def filter_attributes(attributes)
65
+ attributes
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,42 @@
1
+ module DroidServices::Extensions
2
+ module HasResponse
3
+ extend ActiveSupport::Concern
4
+
5
+ def add_error(error)
6
+ @_errors ||= []
7
+ @_errors << error
8
+ end
9
+
10
+ def assign_resource(resource_name, resource)
11
+ @_assignments ||= {}
12
+ @_assignments[resource_name.to_sym] = resource
13
+ end
14
+
15
+ def add_error_unless(error, condition)
16
+ add_error(error) unless condition
17
+ end
18
+
19
+ def add_errors_from(model)
20
+ @_errors ||= []
21
+ if model && model.errors.messages.present?
22
+ model.errors.messages.each do |key, value|
23
+ add_error "#{key}: #{value}"
24
+ end
25
+ end
26
+ end
27
+
28
+ def set_message(message)
29
+ @_message = message
30
+ end
31
+
32
+ def respond_with(resource, custom_resource_name=nil)
33
+ name = custom_resource_name||resource_name
34
+ result = respond_to?(:decorator_class) ? decorator_class.new(resource) : resource
35
+ response = DroidServices::Response.new(name, result)
36
+ response.message = @_message
37
+ response.errors = @_errors
38
+ response.assignments = @_assignments
39
+ response
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,55 @@
1
+ module DroidServices::Extensions
2
+ module HasService
3
+ extend ActiveSupport::Concern
4
+
5
+ def collection
6
+ respond_with decorated_collection, collection_name
7
+ end
8
+
9
+ def build
10
+ respond_with build_resource(nil)
11
+ end
12
+
13
+ def create(custom_attributes=nil)
14
+ resource = build_resource(nil, custom_attributes||resource_attributes)
15
+ invoke_callback(:before_create, resource)
16
+ invoke_callback(:before_save, resource)
17
+ if resource.save
18
+ invoke_callback(:after_create, resource)
19
+ invoke_callback(:after_save, resource)
20
+ set_message("#{resource_name.titleize} successfully created")
21
+ else
22
+ add_errors_from(resource)
23
+ end
24
+ respond_with(resource)
25
+ end
26
+
27
+ def read
28
+ respond_with find_resource(params[:id])
29
+ end
30
+ alias_method :edit, :read
31
+
32
+
33
+ def update(custom_attributes=nil)
34
+ resource = build_resource(params[:id], custom_attributes||resource_attributes)
35
+ invoke_callback(:before_update, resource)
36
+ invoke_callback(:before_save, resource)
37
+ if resource.save
38
+ invoke_callback(:after_update, resource)
39
+ invoke_callback(:after_save, resource)
40
+ set_message("#{resource_name.titleize} successfully updated")
41
+ else
42
+ add_errors_from(resource)
43
+ end
44
+ respond_with(resource)
45
+ end
46
+
47
+ def destroy
48
+ resource = find_resource(params[:id])
49
+ invoke_callback(:before_destroy, resource)
50
+ resource.destroy
51
+ invoke_callback(:after_destroy, resource)
52
+ respond_with(resource)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,46 @@
1
+ class DroidServices::Response
2
+ attr_accessor :message, :errors, :assignments, :result, :resource_name
3
+
4
+ def initialize(resource_name, result)
5
+ @resource_name = resource_name
6
+ @result = result
7
+ @message = nil
8
+ @errors = []
9
+ @assignments = []
10
+ end
11
+
12
+ def with_errors(errors)
13
+ @errors = errors
14
+ self
15
+ end
16
+
17
+ def with_message(message)
18
+ @message = message
19
+ self
20
+ end
21
+
22
+ def success?
23
+ @errors.nil? || @errors.empty?
24
+ end
25
+
26
+ def failure?
27
+ !success?
28
+ end
29
+
30
+ def notice
31
+ message if success?
32
+ end
33
+
34
+ def error
35
+ message || errors.first if failure?
36
+ end
37
+
38
+ def has_error?(error)
39
+ errors && errors.include?(error)
40
+ end
41
+
42
+ def method_missing(method, *args, &block)
43
+ super unless assignments.has_key?(method)
44
+ assignments[method]
45
+ end
46
+ end
@@ -0,0 +1,3 @@
1
+ module DroidServices
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,15 @@
1
+ require "droid_services/version"
2
+ require "droid_services/extensions/has_logger.rb"
3
+ require "droid_services/extensions/has_resource.rb"
4
+ require "droid_services/extensions/has_response.rb"
5
+ require "droid_services/extensions/has_callbacks.rb"
6
+ require "droid_services/extensions/has_service.rb"
7
+ require "droid_services/extensions/has_decorator.rb"
8
+ require "droid_services/base.rb"
9
+ require "droid_services/base_resource.rb"
10
+ require "droid_services/response.rb"
11
+ require "droid_services/callbacks.rb"
12
+ require "droid_services/decorator.rb"
13
+
14
+ module DroidServices
15
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ class Foo; end
4
+ module DroidServices
5
+ describe BaseResource do
6
+ describe 'it should behave like resource' do
7
+ context 'class methods' do
8
+ subject { DroidServices::BaseResource }
9
+ it{ should respond_to(:new) }
10
+ end
11
+ context 'instance methods' do
12
+ subject { DroidServices::BaseResource.new }
13
+ it{ should respond_to(:accessor) }
14
+ it{ should respond_to(:params) }
15
+ it{ should respond_to(:resource_name) }
16
+ it{ should respond_to(:resource_class) }
17
+ it{ should respond_to(:resource_scope) }
18
+ it{ should respond_to(:resource_attributes) }
19
+ it{ should respond_to(:build_resource) }
20
+ it{ should respond_to(:build_collection) }
21
+ it{ should respond_to(:find_resource) }
22
+ it{ should respond_to(:assign_resource) }
23
+ it{ should respond_to(:respond_with) }
24
+ it{ should respond_to(:set_message) }
25
+ it{ should respond_to(:add_error) }
26
+ it{ should respond_to(:add_error_unless) }
27
+ it{ should respond_to(:add_errors_from) }
28
+ it{ should respond_to(:invoke_callback) }
29
+ end
30
+ end
31
+
32
+ subject { DroidServices::BaseResource.new }
33
+ let(:resource) { mock.as_null_object }
34
+ let(:collection) { mock }
35
+ before do
36
+ subject.stub!(:params).and_return({id:123})
37
+ subject.stub!(:find_resource).and_return(resource)
38
+ subject.stub!(:resource_name).and_return('foo')
39
+ end
40
+
41
+ describe '#collection' do
42
+ it 'responds with decorated collection' do
43
+ subject.should_receive(:build_collection).and_return(collection)
44
+ subject.should_receive(:respond_with).with(collection, 'foos')
45
+ subject.collection
46
+ end
47
+ end
48
+
49
+ describe '#build' do
50
+ it 'responds with resource' do
51
+ subject.should_receive(:build_resource).with(nil).and_return(resource)
52
+ subject.should_receive(:respond_with).with(resource)
53
+ subject.build
54
+ end
55
+ end
56
+
57
+ describe '#edit' do
58
+ it 'responds with resource' do
59
+ subject.should_receive(:find_resource)
60
+ subject.should_receive(:respond_with).with(resource)
61
+ subject.edit
62
+ end
63
+ end
64
+
65
+ describe '#read' do
66
+ it 'responds with resource' do
67
+ subject.should_receive(:find_resource)
68
+ subject.should_receive(:respond_with).with(resource)
69
+ subject.read
70
+ end
71
+ end
72
+
73
+ describe '#destroy' do
74
+ it 'responds with resource' do
75
+ subject.should_receive(:find_resource)
76
+ subject.should_receive(:respond_with).with(resource)
77
+ subject.destroy
78
+ end
79
+
80
+ it 'destroys resource' do
81
+ resource.should_receive(:destroy)
82
+ subject.destroy
83
+ end
84
+
85
+ it 'invokes callbacks' do
86
+ subject.should_receive(:invoke_callback).with(:before_destroy, resource)
87
+ subject.should_receive(:invoke_callback).with(:after_destroy, resource)
88
+ subject.destroy
89
+ end
90
+ end
91
+
92
+ describe '#create' do
93
+ let(:params) { {foo: 'bar'} }
94
+ before { subject.stub!(:build_resource).and_return(resource) }
95
+ it 'responds with resource' do
96
+ subject.should_receive(:build_resource).with(nil, params)
97
+ subject.should_receive(:respond_with).with(resource)
98
+ subject.create(params)
99
+ end
100
+
101
+ context 'when resource successfully saved' do
102
+ before { resource.stub!(:save).and_return(true) }
103
+
104
+ it 'invokes callbacks' do
105
+ subject.should_receive(:invoke_callback).with(:before_save, resource)
106
+ subject.should_receive(:invoke_callback).with(:before_create, resource)
107
+ subject.should_receive(:invoke_callback).with(:after_save, resource)
108
+ subject.should_receive(:invoke_callback).with(:after_create, resource)
109
+ subject.create(params)
110
+ end
111
+
112
+ it 'sets message' do
113
+ subject.should_receive(:set_message).with('Foo successfully created')
114
+ subject.create(params)
115
+ end
116
+ end
117
+
118
+ context 'when resource could not be saved' do
119
+ before { resource.stub!(:save).and_return(false) }
120
+
121
+ it 'invokes callbacks' do
122
+ subject.should_receive(:invoke_callback).with(:before_save, resource)
123
+ subject.should_receive(:invoke_callback).with(:before_create, resource)
124
+ subject.should_not_receive(:invoke_callback).with(:after_save, resource)
125
+ subject.should_not_receive(:invoke_callback).with(:after_create, resource)
126
+ subject.create(params)
127
+ end
128
+
129
+ it 'sets error messages' do
130
+ subject.should_receive(:add_errors_from).with(resource)
131
+ subject.create(params)
132
+ end
133
+ end
134
+ end
135
+
136
+ describe '#update' do
137
+ let(:params) { {foo: 'bar'} }
138
+ before { subject.stub!(:build_resource).and_return(resource) }
139
+ it 'responds with resource' do
140
+ subject.should_receive(:build_resource).with(123, params)
141
+ subject.should_receive(:respond_with).with(resource)
142
+ subject.update(params)
143
+ end
144
+
145
+ context 'when resource successfully saved' do
146
+ before { resource.stub!(:save).and_return(true) }
147
+
148
+ it 'invokes callbacks' do
149
+ subject.should_receive(:invoke_callback).with(:before_save, resource)
150
+ subject.should_receive(:invoke_callback).with(:before_update, resource)
151
+ subject.should_receive(:invoke_callback).with(:after_save, resource)
152
+ subject.should_receive(:invoke_callback).with(:after_update, resource)
153
+ subject.update(params)
154
+ end
155
+
156
+ it 'sets message' do
157
+ subject.should_receive(:set_message).with('Foo successfully updated')
158
+ subject.update(params)
159
+ end
160
+ end
161
+
162
+ context 'when resource could not be saved' do
163
+ before { resource.stub!(:save).and_return(false) }
164
+
165
+ it 'invokes callbacks' do
166
+ subject.should_receive(:invoke_callback).with(:before_save, resource)
167
+ subject.should_receive(:invoke_callback).with(:before_update, resource)
168
+ subject.should_not_receive(:invoke_callback).with(:after_save, resource)
169
+ subject.should_not_receive(:invoke_callback).with(:after_update, resource)
170
+ subject.update(params)
171
+ end
172
+
173
+ it 'sets error messages' do
174
+ subject.should_receive(:add_errors_from).with(resource)
175
+ subject.update(params)
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ module DroidServices
4
+ describe Base do
5
+ describe '#new' do
6
+ subject { DroidServices::Base.new({as: :john, params: {foo: 'bar'}})}
7
+ its(:accessor) { should eq(:john) }
8
+ its(:params) { should eq({foo: 'bar'}) }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module DroidServices
4
+ describe Callbacks do
5
+ subject { DroidServices::Callbacks.new(mock) }
6
+
7
+ it { should respond_to(:before_create) }
8
+ it { should respond_to(:after_create) }
9
+
10
+ it { should respond_to(:before_save) }
11
+ it { should respond_to(:after_save) }
12
+
13
+ it { should respond_to(:before_update) }
14
+ it { should respond_to(:after_update) }
15
+
16
+ it { should respond_to(:before_destroy) }
17
+ it { should respond_to(:after_destroy) }
18
+ end
19
+ end