sweet_actions 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/PITCHME.md +224 -0
  8. data/PITCHME.yaml +1 -0
  9. data/README.md +257 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/lib/.DS_Store +0 -0
  14. data/lib/generators/.DS_Store +0 -0
  15. data/lib/generators/rails/.DS_Store +0 -0
  16. data/lib/generators/rails/actions_generator.rb +21 -0
  17. data/lib/generators/rails/resource_override.rb +10 -0
  18. data/lib/generators/rails/templates/.DS_Store +0 -0
  19. data/lib/generators/rails/templates/collect.rb.erb +11 -0
  20. data/lib/generators/rails/templates/create.rb.erb +15 -0
  21. data/lib/generators/rails/templates/destroy.rb.erb +15 -0
  22. data/lib/generators/rails/templates/show.rb.erb +11 -0
  23. data/lib/generators/rails/templates/update.rb.erb +11 -0
  24. data/lib/generators/sweet_actions/install_generator.rb +18 -0
  25. data/lib/generators/sweet_actions/templates/collect_action.rb +10 -0
  26. data/lib/generators/sweet_actions/templates/create_action.rb +14 -0
  27. data/lib/generators/sweet_actions/templates/destroy_action.rb +14 -0
  28. data/lib/generators/sweet_actions/templates/initializer.rb +9 -0
  29. data/lib/generators/sweet_actions/templates/show_action.rb +10 -0
  30. data/lib/generators/sweet_actions/templates/update_action.rb +10 -0
  31. data/lib/sweet_actions.rb +42 -0
  32. data/lib/sweet_actions/.DS_Store +0 -0
  33. data/lib/sweet_actions/action_factory.rb +64 -0
  34. data/lib/sweet_actions/api_action.rb +63 -0
  35. data/lib/sweet_actions/authorization_concerns.rb +23 -0
  36. data/lib/sweet_actions/collect_action.rb +11 -0
  37. data/lib/sweet_actions/configuration.rb +9 -0
  38. data/lib/sweet_actions/controller_concerns.rb +10 -0
  39. data/lib/sweet_actions/create_action.rb +6 -0
  40. data/lib/sweet_actions/destroy_action.rb +19 -0
  41. data/lib/sweet_actions/exceptions.rb +5 -0
  42. data/lib/sweet_actions/railtie.rb +8 -0
  43. data/lib/sweet_actions/read_concerns.rb +14 -0
  44. data/lib/sweet_actions/rest_concerns.rb +47 -0
  45. data/lib/sweet_actions/rest_serializer_concerns.rb +54 -0
  46. data/lib/sweet_actions/routes_helpers.rb +40 -0
  47. data/lib/sweet_actions/save_concerns.rb +51 -0
  48. data/lib/sweet_actions/show_action.rb +9 -0
  49. data/lib/sweet_actions/update_action.rb +6 -0
  50. data/lib/sweet_actions/version.rb +3 -0
  51. data/sweet_actions-0.1.0.gem +0 -0
  52. data/sweet_actions.gemspec +36 -0
  53. metadata +139 -0
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sweet_actions"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
Binary file
Binary file
@@ -0,0 +1,21 @@
1
+ module Rails
2
+ module Generators
3
+ class ActionsGenerator < NamedBase
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def create_actions_folder
7
+ template 'collect.rb.erb', File.join('app/actions', plural_name, 'collect.rb')
8
+ template 'create.rb.erb', File.join('app/actions', plural_name, 'create.rb')
9
+ template 'destroy.rb.erb', File.join('app/actions', plural_name, 'destroy.rb')
10
+ template 'show.rb.erb', File.join('app/actions', plural_name, 'show.rb')
11
+ template 'update.rb.erb', File.join('app/actions', plural_name, 'update.rb')
12
+ end
13
+
14
+ private
15
+
16
+ def module_name
17
+ plural_name.classify.pluralize
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/resource/resource_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ResourceGenerator
7
+ hook_for :decanter, default: true, boolean: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module <%= module_name %>
2
+ class Collect < CollectAction
3
+ # def set_resource
4
+ # resource_class.all
5
+ # end
6
+
7
+ # def authorized?
8
+ # can?(:read, resource) # resource can be a collection
9
+ # end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module <%= module_name %>
2
+ class Create < CreateAction
3
+ # def set_resource
4
+ # resource_class.new(resource_params)
5
+ # end
6
+
7
+ # def authorized?
8
+ # can?(:create, resource)
9
+ # end
10
+
11
+ # def save
12
+ # resource.save
13
+ # end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module <%= module_name %>
2
+ class Destroy < DestroyAction
3
+ # def set_resource
4
+ # resource_class.find(params[:id])
5
+ # end
6
+
7
+ # def authorized?
8
+ # can?(:destroy, resource)
9
+ # end
10
+
11
+ # def destroy
12
+ # resource.destroy
13
+ # end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module <%= module_name %>
2
+ class Show < ShowAction
3
+ # def set_resource
4
+ # resource_class.find(params[:id])
5
+ # end
6
+
7
+ # def authorized?
8
+ # can?(:read, resource)
9
+ # end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module <%= module_name %>
2
+ class Update < UpdateAction
3
+ # def set_resource
4
+ # resource_class.find(params[:id])
5
+ # end
6
+
7
+ # def authorized?
8
+ # can?(:update, resource)
9
+ # end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module SweetActions
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ desc 'Creates a Sweet Actions initializer in your application.'
7
+
8
+ def copy_initializer
9
+ copy_file 'initializer.rb', 'config/initializers/sweet_actions.rb'
10
+ copy_file 'collect_action.rb', 'app/actions/collect_action.rb'
11
+ copy_file 'create_action.rb', 'app/actions/create_action.rb'
12
+ copy_file 'destroy_action.rb', 'app/actions/destroy_action.rb'
13
+ copy_file 'show_action.rb', 'app/actions/show_action.rb'
14
+ copy_file 'update_action.rb', 'app/actions/update_action.rb'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ class CollectAction < SweetActions::CollectAction
2
+ def set_resource
3
+ resource_class.all
4
+ end
5
+
6
+ def authorized?
7
+ # can?(:read, resource)
8
+ false
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ class CreateAction < SweetActions::CreateAction
2
+ def set_resource
3
+ resource_class.new(resource_params)
4
+ end
5
+
6
+ def authorized?
7
+ # can?(:create, resource)
8
+ false
9
+ end
10
+
11
+ def save
12
+ resource.save
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ class DestroyAction < SweetActions::DestroyAction
2
+ def set_resource
3
+ resource_class.find(params[:id])
4
+ end
5
+
6
+ def authorized?
7
+ # can?(:destroy, resource)
8
+ false
9
+ end
10
+
11
+ def destroy
12
+ resource.destroy
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ class SweetActionsController < ApplicationController
2
+ include SweetActions::ControllerConcerns
3
+ end
4
+
5
+ SweetActions.config do |config|
6
+ # REST actions must implement `authorize` method
7
+ # setting to true is the most secure
8
+ config.authorize_rest_requests = true
9
+ end
@@ -0,0 +1,10 @@
1
+ class ShowAction < SweetActions::ShowAction
2
+ def set_resource
3
+ resource_class.find(params[:id])
4
+ end
5
+
6
+ def authorized?
7
+ # can?(:read, resource)
8
+ false
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class UpdateAction < SweetActions::UpdateAction
2
+ def set_resource
3
+ resource_class.find(params[:id])
4
+ end
5
+
6
+ def authorized?
7
+ # can?(:update, resource)
8
+ false
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ module SweetActions
2
+ class << self
3
+ def configuration
4
+ @config ||= SweetActions::Configuration.new
5
+ end
6
+
7
+ def config
8
+ yield configuration
9
+ end
10
+ end
11
+
12
+ ActiveSupport.run_load_hooks(:sweet_actions, self)
13
+ end
14
+
15
+ # overhead
16
+ require 'sweet_actions/version'
17
+ require 'sweet_actions/configuration'
18
+ require 'sweet_actions/exceptions'
19
+
20
+ # base classes
21
+ require 'sweet_actions/action_factory'
22
+ require 'sweet_actions/api_action'
23
+
24
+ # concerns
25
+ require 'sweet_actions/rest_serializer_concerns'
26
+ require 'sweet_actions/rest_concerns'
27
+ require 'sweet_actions/authorization_concerns'
28
+ require 'sweet_actions/save_concerns'
29
+ require 'sweet_actions/read_concerns'
30
+
31
+ # actions
32
+ require 'sweet_actions/collect_action'
33
+ require 'sweet_actions/create_action'
34
+ require 'sweet_actions/update_action'
35
+ require 'sweet_actions/show_action'
36
+ require 'sweet_actions/destroy_action'
37
+
38
+ # helpers
39
+ require 'sweet_actions/controller_concerns'
40
+ require 'sweet_actions/routes_helpers'
41
+
42
+ require 'sweet_actions/railtie' if defined?(::Rails)
@@ -0,0 +1,64 @@
1
+ module SweetActions
2
+ class ActionFactory
3
+ attr_reader :controller, :resource_name, :action, :namespace
4
+
5
+ def initialize(controller, action_name)
6
+ @controller = controller
7
+ path_parameters = env['action_dispatch.request.path_parameters']
8
+ @resource_name = path_parameters[:resource_name]
9
+ @action = action_name
10
+ @namespace = path_parameters[:namespace]
11
+ end
12
+
13
+ def build_action
14
+ action_class.new(controller)
15
+ end
16
+
17
+ private
18
+
19
+ def env
20
+ controller.request.env
21
+ end
22
+
23
+ def action_class
24
+ klass_name = [namespace, resource_module, action_class_name].compact.join('::')
25
+ return klass_name.constantize if klass_defined?(klass_name)
26
+ default_action
27
+ end
28
+
29
+ def resource_module
30
+ return nil unless resource_name
31
+ resource_name.pluralize
32
+ end
33
+
34
+ def action_class_name
35
+ raise 'action is required to be passed into actionFactory' unless action.present?
36
+ action.to_s.classify
37
+ end
38
+
39
+ def default_action
40
+ modules = namespace.split('::')
41
+ class_found = false
42
+ klass_name = nil
43
+
44
+ until class_found || modules.count == 0
45
+ namespace_to_test = modules.join('::')
46
+ target = "#{namespace_to_test}::Defaults::#{action_class_name}"
47
+ if klass_defined?(target)
48
+ klass_name = target
49
+ class_found = true
50
+ end
51
+ modules.pop
52
+ end
53
+ return klass_name.constantize if klass_name.present?
54
+ "#{action_class_name}Action".constantize
55
+ end
56
+
57
+ def klass_defined?(klass_name)
58
+ klass_name.constantize
59
+ return true
60
+ rescue
61
+ return false
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,63 @@
1
+ module SweetActions
2
+ class ApiAction
3
+ attr_reader :controller, :response_data, :response_code
4
+
5
+ def initialize(controller, options = {})
6
+ @controller = controller
7
+ after_init(options)
8
+ end
9
+
10
+ def perform_action
11
+ run_action = Proc.new do
12
+ @response_data = action
13
+ end
14
+
15
+ debug_mode? ? run_action.call : fail_gracefully(run_action)
16
+ end
17
+
18
+ private
19
+
20
+ def after_init(options); end
21
+
22
+ def fail_gracefully(proc)
23
+ @response_code = '200'
24
+ begin
25
+ proc.call
26
+ rescue Exceptions::NotAuthorized => e
27
+ @response_code = '401'
28
+ @response_data = {
29
+ message: 'not authorized'
30
+ }
31
+ rescue StandardError => e
32
+ @response_code = '500'
33
+ @response_data = {
34
+ server_error: e.message
35
+ }
36
+ end
37
+ end
38
+
39
+ def debug_mode?
40
+ ENV['SWEET_ACTION_DEBUG_MODE'] == true
41
+ end
42
+
43
+ def action
44
+ raise "action method is required for #{self.class.name} because it inherits from ApiAction"
45
+ end
46
+
47
+ def path_parameters
48
+ @path_parameters ||= env['action_dispatch.request.path_parameters']
49
+ end
50
+
51
+ def request
52
+ @request ||= controller.request
53
+ end
54
+
55
+ def params
56
+ @params ||= controller.params
57
+ end
58
+
59
+ def env
60
+ request.env
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,23 @@
1
+ module SweetActions
2
+ module AuthorizationConcerns
3
+ private
4
+
5
+ def authorize?
6
+ SweetActions.configuration.authorize_rest_requests
7
+ end
8
+
9
+ def authorize
10
+ return unless authorize?
11
+ return true if authorized?
12
+ unauthorized
13
+ end
14
+
15
+ def authorized?
16
+ raise "authorized? method is required for the #{self.class.name} action"
17
+ end
18
+
19
+ def unauthorized
20
+ raise Exceptions::NotAuthorized
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ module SweetActions
2
+ class CollectAction < ApiAction
3
+ include ReadConcerns
4
+
5
+ private
6
+
7
+ def root_key
8
+ plural_key
9
+ end
10
+ end
11
+ end