snfoil-rails 0.8.2 → 1.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. metadata +145 -64
  3. data/CODE_OF_CONDUCT.md +0 -74
  4. data/MIT-LICENSE +0 -20
  5. data/README.md +0 -28
  6. data/Rakefile +0 -29
  7. data/lib/generators/sn_foil/all/all_generator.rb +0 -50
  8. data/lib/generators/sn_foil/context/context_generator.rb +0 -41
  9. data/lib/generators/sn_foil/context/templates/context.erb +0 -9
  10. data/lib/generators/sn_foil/controller/controller_generator.rb +0 -52
  11. data/lib/generators/sn_foil/controller/templates/api_controller.erb +0 -14
  12. data/lib/generators/sn_foil/controller/templates/controller.erb +0 -14
  13. data/lib/generators/sn_foil/jsonapi_deserializer/jsonapi_deserializer_generator.rb +0 -41
  14. data/lib/generators/sn_foil/jsonapi_deserializer/templates/jsonapi_deserializer.erb +0 -12
  15. data/lib/generators/sn_foil/jsonapi_serializer/jsonapi_serializer_generator.rb +0 -41
  16. data/lib/generators/sn_foil/jsonapi_serializer/templates/jsonapi_serializer.erb +0 -20
  17. data/lib/generators/sn_foil/policy/policy_generator.rb +0 -41
  18. data/lib/generators/sn_foil/policy/templates/policy.erb +0 -22
  19. data/lib/generators/sn_foil/searcher/searcher_generator.rb +0 -41
  20. data/lib/generators/sn_foil/searcher/templates/searcher.erb +0 -7
  21. data/lib/sn_foil/configuration/lazy_jsonapi_serializer.rb +0 -87
  22. data/lib/sn_foil/controller/api.rb +0 -88
  23. data/lib/sn_foil/controller/base.rb +0 -19
  24. data/lib/sn_foil/controller/concerns/change_controller_concern.rb +0 -21
  25. data/lib/sn_foil/controller/concerns/create_controller_concern.rb +0 -38
  26. data/lib/sn_foil/controller/concerns/destroy_controller_concern.rb +0 -40
  27. data/lib/sn_foil/controller/concerns/index_controller_concern.rb +0 -67
  28. data/lib/sn_foil/controller/concerns/setup_controller_concern.rb +0 -85
  29. data/lib/sn_foil/controller/concerns/show_controller_concern.rb +0 -36
  30. data/lib/sn_foil/controller/concerns/update_controller_concern.rb +0 -38
  31. data/lib/sn_foil/jsonapi_deserializer.rb +0 -159
  32. data/lib/sn_foil/jsonapi_serializer.rb +0 -16
  33. data/lib/sn_foil/rails/engine.rb +0 -23
  34. data/lib/sn_foil/rails/version.rb +0 -7
  35. data/lib/sn_foil/rails.rb +0 -25
  36. data/lib/sn_foil/searcher.rb +0 -122
  37. data/lib/snfoil-rails.rb +0 -5
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SnFoil
4
- class JsonapiDeserializerGenerator < Rails::Generators::Base
5
- source_root File.expand_path('templates', __dir__)
6
-
7
- argument :model, type: :string
8
-
9
- class_option :path, desc: 'Base path for file', type: :string, default: 'app/jsonapi_deserializers'
10
-
11
- def add_app_file
12
- file_name = if modules.length.zero?
13
- name
14
- else
15
- "#{modules.join('/')}/#{name}"
16
- end
17
-
18
- template('jsonapi_deserializer.erb', "#{options[:path]}/#{file_name}_jsonapi_deserializer.rb")
19
- end
20
-
21
- private
22
-
23
- def name
24
- @name ||= model.split('/').last.underscore.singularize
25
- end
26
-
27
- def class_name
28
- @class_name ||= name.camelize
29
- end
30
-
31
- def modules
32
- @modules ||= model.split('/')[0..-2].map(&:underscore)
33
- end
34
-
35
- def class_modules
36
- return if modules.length.zero?
37
-
38
- @class_modules ||= "#{modules.map(&:camelize).join('::')}::"
39
- end
40
- end
41
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class <%= class_modules %><%= class_name %>JsonapiDeserializer
4
- include SnFoil::JsonapiDeserializer
5
-
6
- # Add attributes of the model you want to serializer with the following syntax
7
- attributes :id
8
-
9
- # Add relationships with the following syntax
10
- # belongs_to :store, serializer: Jsonapi::StoreJsonapiSerializer
11
- # has_many :locations, serializer: Jsonapi::LocationJsonapiSerializer
12
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SnFoil
4
- class JsonapiSerializerGenerator < Rails::Generators::Base
5
- source_root File.expand_path('templates', __dir__)
6
-
7
- argument :model, type: :string
8
-
9
- class_option :path, desc: 'Base path for file', type: :string, default: 'app/jsonapi_serializers'
10
-
11
- def add_app_file
12
- file_name = if modules.length.zero?
13
- name
14
- else
15
- "#{modules.join('/')}/#{name}"
16
- end
17
-
18
- template('jsonapi_serializer.erb', "#{options[:path]}/#{file_name}_jsonapi_serializer.rb")
19
- end
20
-
21
- private
22
-
23
- def name
24
- @name ||= model.split('/').last.underscore.singularize
25
- end
26
-
27
- def class_name
28
- @class_name ||= name.camelize
29
- end
30
-
31
- def modules
32
- @modules ||= model.split('/')[0..-2].map(&:underscore)
33
- end
34
-
35
- def class_modules
36
- return if modules.length.zero?
37
-
38
- @class_modules ||= "#{modules.map(&:camelize).join('::')}::"
39
- end
40
- end
41
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class <%= class_modules %><%= class_name %>JsonapiSerializer
4
- include SnFoil::JsonapiSerializer
5
-
6
- set_id :id
7
- set_type :<%= name.pluralize.dasherize %>
8
-
9
- # SnFoil::JsonapiSerializer is just a wrapper for jsonapi-serializer (https://github.com/jsonapi-serializer/jsonapi-serializer)
10
- # with some defaults added in
11
-
12
- # Add attributes of the model you want to serializer with the following syntax
13
- # attributes :name
14
- # :description
15
- # :logo_url
16
-
17
- # Add relationships with the following syntax
18
- # belongs_to :store, serializer: Jsonapi::StoreJsonapiSerializer
19
- # has_many :locations, serializer: Jsonapi::LocationJsonapiSerializer
20
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SnFoil
4
- class PolicyGenerator < Rails::Generators::Base
5
- source_root File.expand_path('templates', __dir__)
6
-
7
- argument :model, type: :string
8
-
9
- class_option :path, desc: 'Base path for file', type: :string, default: 'app/policies'
10
-
11
- def add_app_file
12
- file_name = if modules.length.zero?
13
- name
14
- else
15
- "#{modules.join('/')}/#{name}"
16
- end
17
-
18
- template('policy.erb', "#{options[:path]}/#{file_name}_policy.rb")
19
- end
20
-
21
- private
22
-
23
- def name
24
- @name ||= model.split('/').last.underscore.singularize
25
- end
26
-
27
- def class_name
28
- @class_name ||= name.camelize
29
- end
30
-
31
- def modules
32
- @modules ||= model.split('/')[0..-2].map(&:underscore)
33
- end
34
-
35
- def class_modules
36
- return if modules.length.zero?
37
-
38
- @class_modules ||= "#{modules.map(&:camelize).join('::')}::"
39
- end
40
- end
41
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class <%= class_modules %><%= class_name %>Policy
4
- include SnFoil::Policy
5
- # A SnFoil::Policy is just a Pundit policy (https://github.com/varvet/pundit)
6
- # with some defaults
7
- # Available methods: show?, create?, update?, destroy?, index?, associate?
8
-
9
- # def show?
10
- # true
11
- # end
12
-
13
- # class Scope
14
- # # available read-only attributes
15
- # # - scope: the default scope passed into the policy (ex: an ActiveRecord::Relation)
16
- # # - entity: the object that the scope is build around (ex: a User)
17
-
18
- # def resolve
19
- # # the new default scope
20
- # end
21
- # end
22
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SnFoil
4
- class SearcherGenerator < Rails::Generators::Base
5
- source_root File.expand_path('templates', __dir__)
6
-
7
- argument :model, type: :string
8
-
9
- class_option :path, desc: 'Base path for file', type: :string, default: 'app/searchers'
10
-
11
- def add_app_file
12
- file_name = if modules.length.zero?
13
- name
14
- else
15
- "#{modules.join('/')}/#{name}"
16
- end
17
-
18
- template('searcher.erb', "#{options[:path]}/#{file_name}_searcher.rb")
19
- end
20
-
21
- private
22
-
23
- def name
24
- @name ||= model.split('/').last.underscore.pluralize
25
- end
26
-
27
- def class_name
28
- @class_name ||= name.camelize
29
- end
30
-
31
- def modules
32
- @modules ||= model.split('/')[0..-2].map(&:underscore)
33
- end
34
-
35
- def class_modules
36
- return if modules.length.zero?
37
-
38
- @class_modules ||= "#{modules.map(&:camelize).join('::')}::"
39
- end
40
- end
41
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class <%= class_modules %><%= class_name %>Searcher
4
- include SnFoil::Searcher
5
-
6
- model <%= class_name.singularize %>
7
- end
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SnFoil
4
- module Configuration
5
- module LazyJsonapiSerializer
6
- extend ActiveSupport::Concern
7
-
8
- class << self
9
- def belongs_to(relationship_name, options = {}, &block)
10
- block = belongs_to_optimized_block(relationship_name, options, &block)
11
- super(relationship_name, options, &block)
12
- end
13
-
14
- def has_one(relationship_name, options = {}, &block) # rubocop:disable Naming/PredicateName reason: method override
15
- super(relationship_name, has_relation_optimized_options(relationship_name, options), &block)
16
- end
17
-
18
- def has_many(relationship_name, options = {}, &block) # rubocop:disable Naming/PredicateName reason: method override
19
- super(relationship_name, has_relation_optimized_options(relationship_name, options), &block)
20
- end
21
-
22
- private
23
-
24
- # We need to parse the include block because FastJsonAPI does not allow access to the pre-parsed includes
25
- def parse_include(params)
26
- return [] unless params[:include]
27
-
28
- if params[:include].is_a?(String)
29
- params[:include].split(',')
30
- else
31
- params[:include]
32
- end.map { |r| r.to_s.dasherize }.join(',')
33
- end
34
-
35
- def lookup_full_object_for_belongs_to(record, relationship_name, options, params)
36
- return unless parse_include(params).include?(relationship_name.to_s.dasherize)
37
-
38
- record.send(options[:object_method_name] || relationship_name)
39
- end
40
-
41
- def create_substitute_object_for_belongs_to(record, relationship_name, options)
42
- relationship_id = options[:id_method_name] || "#{relationship_name}_id".to_sym
43
- OpenStruct.new(id: record.send(relationship_id))
44
- end
45
-
46
- def belongs_to_optimized_block(relationship_name, options = {}, &block)
47
- return block if options[:skip_optimization] == true || block
48
-
49
- proc do |record, params|
50
- if params && params[:include]
51
- lookup_full_object(record_for_belongs_to, relationship_name, options, params)
52
- else
53
- create_substitute_object_for_belongs_to(record, relationship_name, options)
54
- end
55
- end
56
- end
57
-
58
- def create_included_proc_for_has_relation(relationship_name)
59
- proc do |_record, params|
60
- if params && params[:include]
61
- parse_include(params).include?(relationship_name.to_s.dasherize)
62
- else
63
- false
64
- end
65
- end
66
- end
67
-
68
- def create_if_proc_for_has_relation(if_proc, included_proc)
69
- if if_proc.present?
70
- proc do |record, params|
71
- FastJsonapi.call_proc(included_proc, record, params) && FastJsonapi.call_proc(if_proc, record, params)
72
- end
73
- else
74
- included_proc
75
- end
76
- end
77
-
78
- def has_relation_optimized_options(relationship_name, options) # rubocop:disable Naming/PredicateName reason: method override
79
- return options if options[:skip_optimization] == true
80
-
81
- options[:if] = create_if_proc_for_has_relation(options[:if], create_included_proc_for_has_relation(relationship_name))
82
- options
83
- end
84
- end
85
- end
86
- end
87
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'action_controller/api'
4
- require_relative 'base'
5
-
6
- module SnFoil
7
- module Controller
8
- class API < SnFoil::Controller::Base
9
- class << self
10
- attr_reader :i_serializer, :i_deserializer
11
-
12
- def serializer(klass = nil)
13
- @i_serializer = klass
14
- end
15
-
16
- def deserializer(klass = nil)
17
- @i_deserializer = klass
18
- end
19
- end
20
-
21
- def serializer(**options)
22
- options[:serializer] || self.class.i_serializer
23
- end
24
-
25
- def deserializer(**options)
26
- options[:deserializer] || self.class.i_deserializer
27
- end
28
-
29
- def setup_options(**options)
30
- inject_deserialized_params(super)
31
- end
32
-
33
- def setup_create(**options)
34
- super(**options.merge(deserialize: true))
35
- end
36
-
37
- def setup_update(**options)
38
- super(**options.merge(deserialize: true))
39
- end
40
-
41
- def render_change(model, **options)
42
- if model.errors.empty?
43
- params
44
- render json: serializer(**options).new(model,
45
- **options,
46
- params: (options[:controller_params] || options[:params] || {})
47
- .merge(current_entity: context_entity)).serializable_hash
48
- else
49
- render json: model.errors, status: :unprocessable_entity
50
- end
51
- end
52
-
53
- def render_destroy(model, **_options)
54
- if model.errors.empty?
55
- render json: {}, status: :no_content
56
- else
57
- render json: model.errors, status: :unprocessable_entity
58
- end
59
- end
60
-
61
- def render_index(results, **options)
62
- render json: serializer(**options).new(paginate(results, **options),
63
- **options,
64
- params: (options[:controller_params] || options[:params] || {})
65
- .merge(current_entity: context_entity),
66
- meta: meta(results, **options))
67
- .serializable_hash
68
- end
69
-
70
- def render_show(model, **options)
71
- render json: serializer(**options).new(model,
72
- **options,
73
- params: (options[:controller_params] || options[:params] || {})
74
- .merge(current_entity: context_entity)).serializable_hash
75
- end
76
-
77
- private
78
-
79
- def inject_deserialized_params(**options)
80
- return options unless options[:params].present? && options[:deserialize] == true
81
- return options unless deserializer(**options)
82
-
83
- options[:params] = deserializer(**options).new(options[:params], **options).to_h
84
- options
85
- end
86
- end
87
- end
88
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'concerns/create_controller_concern'
4
- require_relative 'concerns/destroy_controller_concern'
5
- require_relative 'concerns/index_controller_concern'
6
- require_relative 'concerns/show_controller_concern'
7
- require_relative 'concerns/update_controller_concern'
8
-
9
- module SnFoil
10
- module Controller
11
- class Base < ActionController::Base # rubocop:disable Rails/ApplicationController
12
- include Concerns::CreateControllerConcern
13
- include Concerns::DestroyControllerConcern
14
- include Concerns::IndexControllerConcern
15
- include Concerns::ShowControllerConcern
16
- include Concerns::UpdateControllerConcern
17
- end
18
- end
19
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
-
5
- module SnFoil
6
- module Controller
7
- module Concerns
8
- module ChangeControllerConcern
9
- extend ActiveSupport::Concern
10
-
11
- def render_change(model, **_options)
12
- if model.errors.empty?
13
- render model
14
- else
15
- render model.errors, status: :unprocessable_entity
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
- require_relative 'change_controller_concern'
6
-
7
- module SnFoil
8
- module Controller
9
- module Concerns
10
- module CreateControllerConcern
11
- extend ActiveSupport::Concern
12
-
13
- included do
14
- include SetupControllerConcern
15
- include ChangeControllerConcern
16
- end
17
-
18
- def create(**options)
19
- options = setup_create(**options)
20
- model = process_create(**options)
21
- render_create(model, **options)
22
- end
23
-
24
- def setup_create(**options)
25
- setup_options(**options)
26
- end
27
-
28
- def process_create(**options)
29
- current_context(**options).create(**options)
30
- end
31
-
32
- def render_create(model, **options)
33
- render_change(model, **options)
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
-
6
- module SnFoil
7
- module Controller
8
- module Concerns
9
- module DestroyControllerConcern
10
- extend ActiveSupport::Concern
11
-
12
- included do
13
- include SetupControllerConcern
14
- end
15
-
16
- def destroy(**options)
17
- options = setup_destroy(**options)
18
- model = process_destroy(**options)
19
- render_destroy(model, **options)
20
- end
21
-
22
- def setup_destroy(**options)
23
- setup_options(**options)
24
- end
25
-
26
- def process_destroy(**options)
27
- current_context(**options).destroy(**options)
28
- end
29
-
30
- def render_destroy(model, **_options)
31
- if model.errors.empty?
32
- render nil
33
- else
34
- render model.errors, status: :unprocessable_entity
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
-
6
- module SnFoil
7
- module Controller
8
- module Concerns
9
- module IndexControllerConcern
10
- extend ActiveSupport::Concern
11
-
12
- included do
13
- include SetupControllerConcern
14
- end
15
-
16
- def index(**options)
17
- options = setup_index(**options)
18
- results = process_index(**options)
19
- render_index(results, **options)
20
- end
21
-
22
- def setup_index(**options)
23
- setup_options(**options)
24
- end
25
-
26
- def process_index(**options)
27
- current_context(**options).index(options)
28
- end
29
-
30
- def render_index(results, **options)
31
- render paginate(results, **options), meta: meta(results, options)
32
- end
33
-
34
- def paginate(results, **options)
35
- return results unless results.respond_to?(:page)
36
-
37
- results.page(page(**options))
38
- .per(per_page(**options))
39
- end
40
-
41
- def page(**options)
42
- (options.dig(:params, :page) || 1).to_i
43
- end
44
-
45
- def per_page(**options)
46
- per_page_param = (options.dig(:params, :per_page) || 10).to_i
47
- return 1000 if per_page_param.zero? || per_page_param > 1000
48
-
49
- per_page_param
50
- end
51
-
52
- def meta(results, **options)
53
- results = paginate(results, **options)
54
- total_pages = results.respond_to?(:total_pages) ? results.total_pages : nil
55
- total_count = results.respond_to?(:total_count) ? results.total_count : nil
56
-
57
- {
58
- page: page(**options),
59
- pages: total_pages,
60
- total: total_count,
61
- per: per_page(**options)
62
- }
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
-
5
- module SnFoil
6
- module Controller
7
- module Concerns
8
- module SetupControllerConcern
9
- extend ActiveSupport::Concern
10
-
11
- class_methods do
12
- attr_reader :i_context
13
-
14
- def context(klass = nil)
15
- @i_context = klass
16
- end
17
- end
18
-
19
- def context(**options)
20
- options[:context] || self.class.i_context
21
- end
22
-
23
- def setup_options(**options)
24
- options = inject_params(**options)
25
- options = inject_id(**options)
26
- options = inject_includes(**options)
27
- inject_controller_action(**options)
28
- end
29
-
30
- def current_context(**options)
31
- @current_context ||= context(**options).new(context_entity)
32
- end
33
-
34
- protected
35
-
36
- def pundit_not_authorized
37
- head :forbidden
38
- end
39
-
40
- private
41
-
42
- # Grab the rails params and inject them into the options
43
- def inject_params(**options)
44
- return options if options[:params]
45
- return options unless params
46
-
47
- options[:params] = params.to_unsafe_h.deep_symbolize_keys
48
- options[:controller_params] = options[:params]
49
- options
50
- end
51
-
52
- def inject_id(**options)
53
- return options if options[:id]
54
-
55
- options[:id] = id if defined? id
56
- options[:id] ||= options[:params][:id]
57
- options
58
- end
59
-
60
- def inject_includes(**options)
61
- return options if options[:include]
62
- return options unless options.dig(:params, :include)
63
-
64
- options[:include] = options.dig(:params, :include)
65
- .split(',')
66
- .map { |item| item.underscore.to_sym }
67
- options
68
- end
69
-
70
- def inject_controller_action(**options)
71
- return options if options[:controller_action]
72
- return options unless options.dig(:params, :action)
73
-
74
- options[:controller_action] = options[:params][:action]
75
- options
76
- end
77
-
78
- def context_entity
79
- return current_entity if defined? current_entity
80
- return current_user if defined? current_user
81
- end
82
- end
83
- end
84
- end
85
- end