wallaby-core 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/app/controllers/wallaby/application_controller.rb +84 -0
- data/app/controllers/wallaby/resources_controller.rb +381 -0
- data/app/controllers/wallaby/secure_controller.rb +81 -0
- data/app/security/ability.rb +13 -0
- data/config/locales/wallaby.en.yml +140 -0
- data/config/locales/wallaby_class.en.yml +30 -0
- data/config/routes.rb +39 -0
- data/lib/adaptors/wallaby/custom.rb +7 -0
- data/lib/adaptors/wallaby/custom/default_provider.rb +9 -0
- data/lib/adaptors/wallaby/custom/model_decorator.rb +71 -0
- data/lib/adaptors/wallaby/custom/model_finder.rb +13 -0
- data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +14 -0
- data/lib/adaptors/wallaby/custom/model_service_provider.rb +48 -0
- data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +72 -0
- data/lib/authorizers/wallaby/default_authorization_provider.rb +58 -0
- data/lib/authorizers/wallaby/model_authorizer.rb +100 -0
- data/lib/authorizers/wallaby/pundit_authorization_provider.rb +89 -0
- data/lib/concerns/wallaby/authorizable.rb +103 -0
- data/lib/concerns/wallaby/baseable.rb +36 -0
- data/lib/concerns/wallaby/decoratable.rb +101 -0
- data/lib/concerns/wallaby/defaultable.rb +38 -0
- data/lib/concerns/wallaby/engineable.rb +61 -0
- data/lib/concerns/wallaby/fieldable.rb +78 -0
- data/lib/concerns/wallaby/paginatable.rb +72 -0
- data/lib/concerns/wallaby/rails_overridden_methods.rb +42 -0
- data/lib/concerns/wallaby/resourcable.rb +149 -0
- data/lib/concerns/wallaby/servicable.rb +68 -0
- data/lib/concerns/wallaby/shared_helpers.rb +22 -0
- data/lib/concerns/wallaby/themeable.rb +40 -0
- data/lib/decorators/wallaby/resource_decorator.rb +189 -0
- data/lib/errors/wallaby/cell_handling.rb +6 -0
- data/lib/errors/wallaby/forbidden.rb +6 -0
- data/lib/errors/wallaby/general_error.rb +6 -0
- data/lib/errors/wallaby/invalid_error.rb +6 -0
- data/lib/errors/wallaby/model_not_found.rb +11 -0
- data/lib/errors/wallaby/not_authenticated.rb +6 -0
- data/lib/errors/wallaby/not_found.rb +6 -0
- data/lib/errors/wallaby/not_implemented.rb +6 -0
- data/lib/errors/wallaby/resource_not_found.rb +11 -0
- data/lib/errors/wallaby/unprocessable_entity.rb +6 -0
- data/lib/forms/wallaby/form_builder.rb +60 -0
- data/lib/helpers/wallaby/application_helper.rb +79 -0
- data/lib/helpers/wallaby/base_helper.rb +65 -0
- data/lib/helpers/wallaby/configuration_helper.rb +18 -0
- data/lib/helpers/wallaby/form_helper.rb +62 -0
- data/lib/helpers/wallaby/index_helper.rb +84 -0
- data/lib/helpers/wallaby/links_helper.rb +213 -0
- data/lib/helpers/wallaby/resources_helper.rb +52 -0
- data/lib/helpers/wallaby/secure_helper.rb +54 -0
- data/lib/helpers/wallaby/styling_helper.rb +82 -0
- data/lib/interfaces/wallaby/mode.rb +72 -0
- data/lib/interfaces/wallaby/model_authorization_provider.rb +99 -0
- data/lib/interfaces/wallaby/model_decorator.rb +168 -0
- data/lib/interfaces/wallaby/model_finder.rb +12 -0
- data/lib/interfaces/wallaby/model_pagination_provider.rb +107 -0
- data/lib/interfaces/wallaby/model_service_provider.rb +84 -0
- data/lib/paginators/wallaby/model_paginator.rb +115 -0
- data/lib/paginators/wallaby/resource_paginator.rb +12 -0
- data/lib/parsers/wallaby/parser.rb +34 -0
- data/lib/renderers/wallaby/cell.rb +137 -0
- data/lib/renderers/wallaby/cell_resolver.rb +89 -0
- data/lib/renderers/wallaby/custom_lookup_context.rb +64 -0
- data/lib/renderers/wallaby/custom_partial_renderer.rb +33 -0
- data/lib/renderers/wallaby/custom_renderer.rb +16 -0
- data/lib/responders/wallaby/json_api_responder.rb +101 -0
- data/lib/responders/wallaby/resources_responder.rb +28 -0
- data/lib/routes/wallaby/resources_router.rb +72 -0
- data/lib/servicers/wallaby/model_servicer.rb +154 -0
- data/lib/services/wallaby/engine_name_finder.rb +22 -0
- data/lib/services/wallaby/engine_url_for.rb +46 -0
- data/lib/services/wallaby/link_options_normalizer.rb +19 -0
- data/lib/services/wallaby/map/mode_mapper.rb +27 -0
- data/lib/services/wallaby/map/model_class_collector.rb +49 -0
- data/lib/services/wallaby/map/model_class_mapper.rb +38 -0
- data/lib/services/wallaby/prefixes_builder.rb +66 -0
- data/lib/services/wallaby/sorting/hash_builder.rb +19 -0
- data/lib/services/wallaby/sorting/link_builder.rb +69 -0
- data/lib/services/wallaby/sorting/next_builder.rb +63 -0
- data/lib/services/wallaby/sorting/single_builder.rb +20 -0
- data/lib/services/wallaby/type_renderer.rb +50 -0
- data/lib/support/action_dispatch/routing/mapper.rb +75 -0
- data/lib/tree/wallaby/node.rb +25 -0
- data/lib/utils/wallaby/cell_utils.rb +34 -0
- data/lib/utils/wallaby/field_utils.rb +43 -0
- data/lib/utils/wallaby/filter_utils.rb +20 -0
- data/lib/utils/wallaby/model_utils.rb +51 -0
- data/lib/utils/wallaby/module_utils.rb +46 -0
- data/lib/utils/wallaby/params_utils.rb +14 -0
- data/lib/utils/wallaby/preload_utils.rb +44 -0
- data/lib/utils/wallaby/test_utils.rb +34 -0
- data/lib/utils/wallaby/utils.rb +27 -0
- data/lib/wallaby/configuration.rb +103 -0
- data/lib/wallaby/configuration/features.rb +24 -0
- data/lib/wallaby/configuration/mapping.rb +140 -0
- data/lib/wallaby/configuration/metadata.rb +23 -0
- data/lib/wallaby/configuration/models.rb +46 -0
- data/lib/wallaby/configuration/pagination.rb +30 -0
- data/lib/wallaby/configuration/security.rb +98 -0
- data/lib/wallaby/configuration/sorting.rb +28 -0
- data/lib/wallaby/constants.rb +45 -0
- data/lib/wallaby/core.rb +117 -0
- data/lib/wallaby/core/version.rb +7 -0
- data/lib/wallaby/engine.rb +43 -0
- data/lib/wallaby/map.rb +170 -0
- metadata +222 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Type renderer
|
5
|
+
class TypeRenderer
|
6
|
+
class << self
|
7
|
+
# Render partial
|
8
|
+
# @param view [ActionView]
|
9
|
+
# @param options [Hash]
|
10
|
+
# @param locals [Hash]
|
11
|
+
# @return [String] HTML
|
12
|
+
def render(view, options = {}, locals = {}, &block)
|
13
|
+
locals[:object] ||= locals[:form].try :object
|
14
|
+
check locals
|
15
|
+
complete locals, view.params[:action]
|
16
|
+
view.render options, locals, &block
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# @param locals [Hash]
|
22
|
+
# @raise [ArgumentError] if form is set but blank
|
23
|
+
# @raise [ArgumentError] if field_name is not provided
|
24
|
+
# @raise [ArgumentError] if object is not decorated
|
25
|
+
def check(locals)
|
26
|
+
raise ArgumentError, I18n.t('errors.required', subject: 'form') if locals.key?(:form) && locals[:form].blank?
|
27
|
+
raise ArgumentError, I18n.t('errors.required', subject: 'field_name') if locals[:field_name].blank?
|
28
|
+
raise ArgumentError, 'Object is not decorated.' unless locals[:object].is_a? ResourceDecorator
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param locals [Hash]
|
32
|
+
# @param action [String]
|
33
|
+
def complete(locals, action)
|
34
|
+
action_name = CellUtils.to_action_prefix action
|
35
|
+
locals[:metadata] = locals[:object].public_send :"#{action_name}_metadata_of", locals[:field_name]
|
36
|
+
locals[:value] = locals[:object].public_send locals[:field_name]
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param options [String]
|
40
|
+
# @param view [ActionView]
|
41
|
+
# @return [String] partial path string
|
42
|
+
# @return [String] blank string
|
43
|
+
def find_partial(options, view)
|
44
|
+
formats = [view.request.format.to_sym]
|
45
|
+
lookup = view.lookup_context
|
46
|
+
lookup.find_template options, lookup.prefixes, true, [], formats: formats
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module Routing
|
5
|
+
# Re-open `ActionDispatch::Routing::Mapper` to add route helpers for Wallaby.
|
6
|
+
class Mapper
|
7
|
+
# Generate **resourceful** routes that works for Wallaby.
|
8
|
+
# @example To generate resourceful routes that works for Wallaby:
|
9
|
+
# wresources :postcodes
|
10
|
+
# # => same effect as
|
11
|
+
# resources(
|
12
|
+
# :postcodes,
|
13
|
+
# path: ':resources',
|
14
|
+
# defaults: { resources: :postcodes },
|
15
|
+
# constraints: { resources: :postcodes }
|
16
|
+
# )
|
17
|
+
# @param resource_names [Array<String, Symbol>]
|
18
|
+
# @see https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resources
|
19
|
+
# ActionDispatch::Routing::Mapper::Resources#resources
|
20
|
+
def wresources(*resource_names, &block)
|
21
|
+
options = resource_names.extract_options!.dup
|
22
|
+
resource_names.each do |resource_name|
|
23
|
+
new_options = wallaby_resources_options_for resource_name, options
|
24
|
+
resources resource_name, new_options, &block
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Generate **resourceful** routes that works for Wallaby.
|
29
|
+
# @example To generate resourceful routes that works for Wallaby:
|
30
|
+
# wresource :profile
|
31
|
+
# # => same effect as
|
32
|
+
# resource(
|
33
|
+
# :profile,
|
34
|
+
# path: ':resource',
|
35
|
+
# defaults: { resource: :profile, resources: :profiles },
|
36
|
+
# constraints: { resource: :profile, resources: :profiles }
|
37
|
+
# )
|
38
|
+
# @param resource_names [Array<String, Symbol>]
|
39
|
+
# @see https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resource
|
40
|
+
# ActionDispatch::Routing::Mapper::Resources#resource
|
41
|
+
def wresource(*resource_names, &block)
|
42
|
+
options = resource_names.extract_options!.dup
|
43
|
+
resource_names.each do |resource_name|
|
44
|
+
new_options = wallaby_resource_options_for resource_name, options
|
45
|
+
resource resource_name, new_options, &block
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
# Fill in the **resources** options required by Wallaby
|
52
|
+
# @param resources_name [String, Symbol]
|
53
|
+
# @param options [Hash]
|
54
|
+
def wallaby_resources_options_for(resources_name, options)
|
55
|
+
{ path: ':resources' }.merge!(options).tap do |new_options|
|
56
|
+
%i(defaults constraints).each do |key|
|
57
|
+
new_options[key] = { resources: resources_name }.merge!(new_options[key] || {})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Fill in the **resource** options required by Wallaby
|
63
|
+
# @param resource_name [String, Symbol]
|
64
|
+
# @param options [Hash]
|
65
|
+
def wallaby_resource_options_for(resource_name, options)
|
66
|
+
plural_resources = Wallaby::ModelUtils.to_resources_name resource_name
|
67
|
+
{ path: ':resource' }.merge!(options).tap do |new_options|
|
68
|
+
%i(defaults constraints).each do |key|
|
69
|
+
new_options[key] = { resource: resource_name, resources: plural_resources }.merge!(new_options[key] || {})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# To present classes in tree structure.
|
5
|
+
class Node
|
6
|
+
# @!attribute [r] klass
|
7
|
+
# Represent the current class
|
8
|
+
attr_reader :klass
|
9
|
+
# @!attribute parent
|
10
|
+
# Represent the parent class of current class
|
11
|
+
attr_accessor :parent
|
12
|
+
|
13
|
+
delegate :name, to: :klass
|
14
|
+
|
15
|
+
# @param klass [Class]
|
16
|
+
def initialize(klass)
|
17
|
+
@klass = klass
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Array<Class>] a list of children classes
|
21
|
+
def children
|
22
|
+
@children ||= []
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Cell utils
|
5
|
+
module CellUtils
|
6
|
+
class << self
|
7
|
+
# Render a cell and produce output
|
8
|
+
# @param context [ActionView::Context]
|
9
|
+
# @param file_name [String]
|
10
|
+
# @param locals [Hash]
|
11
|
+
# @return [String] output
|
12
|
+
def render(context, file_name, locals = {}, &block)
|
13
|
+
snake_class = file_name[%r{(?<=app/).+(?=\.rb)}].split(SLASH, 2).last
|
14
|
+
cell_class = snake_class.camelize.constantize
|
15
|
+
Rails.logger.info " Rendered [cell] #{file_name}"
|
16
|
+
cell_class.new(context, locals).render_complete(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Check if a partial is a cell or not
|
20
|
+
# @param partial_path [String]
|
21
|
+
# @return [true] if partial is a `rb` file
|
22
|
+
# @return [false] otherwise
|
23
|
+
def find_cell(*partials)
|
24
|
+
partials.find { |partial| partial.end_with? '.rb' }
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param action_name [String, Symbol]
|
28
|
+
# @return [String, Symbol] action prefix
|
29
|
+
def to_action_prefix(action_name)
|
30
|
+
FORM_ACTIONS[action_name] || action_name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Field utils
|
5
|
+
module FieldUtils
|
6
|
+
class << self
|
7
|
+
# Find the first field that meets the first condition.
|
8
|
+
# @example to find the possible text field
|
9
|
+
# Wallaby::FieldUtils.first_field_by({ name: /name|title/ }, { type: 'string' }, fields)
|
10
|
+
# # => if any field name that has `name` or `title`, return this field
|
11
|
+
# # => otherwise, find the first field that has type `string`
|
12
|
+
# @param conditions [Array<Hash>]
|
13
|
+
# @param fields [Hash] field metadata
|
14
|
+
# @return [String, Symbol] field name
|
15
|
+
def first_field_by(*conditions, fields)
|
16
|
+
return if [conditions, fields].any?(&:blank?)
|
17
|
+
|
18
|
+
conditions.each do |condition|
|
19
|
+
fields.each do |field_name, metadata|
|
20
|
+
return field_name if meet? field_name, metadata.with_indifferent_access, condition
|
21
|
+
end
|
22
|
+
end
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
# @param field_name [String]
|
29
|
+
# @param metadata [Hash]
|
30
|
+
# @param condition [Hash]
|
31
|
+
# @return [true] if field's metadata meets the condition
|
32
|
+
# @return [true] otherwise
|
33
|
+
def meet?(field_name, metadata, condition)
|
34
|
+
condition.all? do |key, requirement|
|
35
|
+
operator = requirement.is_a?(::Regexp) ? '=~' : '=='
|
36
|
+
value = metadata[key]
|
37
|
+
value ||= field_name.to_s if key.to_sym == :name
|
38
|
+
ModuleUtils.try_to value, operator, requirement
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Filter utils
|
5
|
+
module FilterUtils
|
6
|
+
# Find filter name in the following precedences from high to low:
|
7
|
+
#
|
8
|
+
# - `filter_name` argument
|
9
|
+
# - filters that has been marked as default
|
10
|
+
# - `:all`
|
11
|
+
# @param filter_name [String, Symbol] filter name
|
12
|
+
# @param filters [Hash] filter metadata
|
13
|
+
# @return [String, Symbol]
|
14
|
+
def self.filter_name_by(filter_name, filters)
|
15
|
+
filter = filter_name # from param
|
16
|
+
filter ||= filters.find { |_k, v| v[:default] }.try(:first) # from default value
|
17
|
+
filter || :all # last resort
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Utils for model
|
5
|
+
module ModelUtils
|
6
|
+
class << self
|
7
|
+
# Convert model class (e.g. `Namespace::Product`) into resources name (e.g. `namespace::products`)
|
8
|
+
# @param model_class [Class, String] model class
|
9
|
+
# @return [String] resources name
|
10
|
+
def to_resources_name(model_class)
|
11
|
+
return EMPTY_STRING if model_class.blank?
|
12
|
+
|
13
|
+
model_class.to_s.underscore.gsub(SLASH, COLONS).pluralize
|
14
|
+
end
|
15
|
+
|
16
|
+
# Produce model label (e.g. `Namespace / Product`) for model class (e.g. `Namespace::Product`)
|
17
|
+
# @param model_class [Class, String] model class
|
18
|
+
# @return [String] model label
|
19
|
+
def to_model_label(model_class)
|
20
|
+
# TODO: change to use i18n translation
|
21
|
+
return EMPTY_STRING if model_class.blank?
|
22
|
+
|
23
|
+
model_class_name = to_model_name model_class
|
24
|
+
model_class_name.titleize.gsub(SLASH, SPACE + SLASH + SPACE)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Convert resources name (e.g. `namespace::products`) into model class (e.g. `Namespace::Product`)
|
28
|
+
# @param resources_name [String] resources name
|
29
|
+
# @return [Class] model class
|
30
|
+
# @return [nil] when not found
|
31
|
+
def to_model_class(resources_name)
|
32
|
+
return if resources_name.blank?
|
33
|
+
|
34
|
+
class_name = to_model_name resources_name
|
35
|
+
class_name.constantize
|
36
|
+
rescue NameError
|
37
|
+
Rails.logger.warn I18n.t('errors.not_found.model', model: class_name)
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Convert resources name (e.g. `namespace::products`) into model name (e.g. `Namespace::Product`)
|
42
|
+
# @param resources_name [String] resources name
|
43
|
+
# @return [String] model name
|
44
|
+
def to_model_name(resources_name)
|
45
|
+
return EMPTY_STRING if resources_name.blank?
|
46
|
+
|
47
|
+
resources_name.to_s.singularize.gsub(COLONS, SLASH).camelize
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Utils for module and class
|
5
|
+
module ModuleUtils
|
6
|
+
class << self
|
7
|
+
# A helper method to check if subject responds to given method and to return the result if so
|
8
|
+
# @param subject [Object]
|
9
|
+
# @param method_id [String, Symbol]
|
10
|
+
# @param args [Array] a list of arguments
|
11
|
+
# @return [Object] result from executing given method on subject
|
12
|
+
# @return [nil] if subject doesn't respond to given method
|
13
|
+
def try_to(subject, method_id, *args, &block)
|
14
|
+
return if method_id.blank?
|
15
|
+
|
16
|
+
subject.respond_to?(method_id) && subject.public_send(method_id, *args, &block) || nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Check whether a class is anonymous or not
|
20
|
+
# @param klass [Class]
|
21
|
+
# @return [true] if a class is anonymous
|
22
|
+
# @return [false] otherwise
|
23
|
+
def anonymous_class?(klass)
|
24
|
+
klass.name.blank? || klass.to_s.start_with?('#<Class')
|
25
|
+
end
|
26
|
+
|
27
|
+
# Check if a child class inherits from parent class
|
28
|
+
# @param child [Class] child class
|
29
|
+
# @param parent [Class] parent class
|
30
|
+
# @raise [ArgumentError] if given class is not a child of the other class
|
31
|
+
def inheritance_check(child, parent)
|
32
|
+
return unless child && parent
|
33
|
+
return if child < parent
|
34
|
+
|
35
|
+
raise ::ArgumentError, I18n.t('errors.invalid.inheritance', klass: child, parent: parent)
|
36
|
+
end
|
37
|
+
|
38
|
+
# If block is given, run the block. Otherwise, return subject
|
39
|
+
# @param subject [Object]
|
40
|
+
# @yield [subject]
|
41
|
+
def yield_for(subject)
|
42
|
+
block_given? ? yield(subject) : subject
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Hash utils
|
5
|
+
module ParamsUtils
|
6
|
+
class << self
|
7
|
+
# @param params [Array<Hash>]
|
8
|
+
# @return [Hash] combined hash that removes empty values
|
9
|
+
def presence(*params)
|
10
|
+
params.reduce({}, :merge).delete_if { |_, v| v.nil? || v == '' }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Preload utils
|
5
|
+
module PreloadUtils
|
6
|
+
class << self
|
7
|
+
# Preload all files under app folder
|
8
|
+
def require_all
|
9
|
+
eager_load_paths.map(&method(:require_one))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Require files under a load path
|
13
|
+
# @param load_path [String, Pathname]
|
14
|
+
# @see https://api.rubyonrails.org/classes/Rails/Engine.html#method-i-eager_load-21 Rails::Engine#eager_load!
|
15
|
+
def require_one(load_path)
|
16
|
+
Dir.glob("#{load_path}/**/*.rb").sort.each(&method(:load_class_for))
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# @return [Array<String, Pathname>] a list of sorted eager load paths which lists `app/models`
|
22
|
+
# at highest precedence
|
23
|
+
def eager_load_paths
|
24
|
+
Rails.configuration.eager_load_paths.sort_by do |path|
|
25
|
+
- path.index(%r{/models$}).to_i
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# `constantize` is used to make Rails to handle all sort of load errors
|
30
|
+
#
|
31
|
+
# NOTE: don't try to use `ActiveSupport::Dependencies::Loadable.require_dependency`.
|
32
|
+
# As `require_dependency` does not take care all errors raised when class/module is loaded.
|
33
|
+
# @param file_path [Pathname, String]
|
34
|
+
def load_class_for(file_path)
|
35
|
+
module_name = file_path[%r{app/[^/]+/(.+)\.rb}, 1].gsub('/concerns/', '/')
|
36
|
+
class_name = module_name.camelize
|
37
|
+
class_name.constantize unless Module.const_defined? class_name
|
38
|
+
rescue NameError, LoadError => e
|
39
|
+
Rails.logger.debug " [WALLABY] Preload warning: #{e.message} from #{file_path}"
|
40
|
+
Rails.logger.debug e.backtrace.slice(0, 5)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# Utils for test
|
5
|
+
module TestUtils
|
6
|
+
class << self
|
7
|
+
# @param context
|
8
|
+
# @param controller_class [Class]
|
9
|
+
def around_crud(context, controller_class = nil)
|
10
|
+
context.before do
|
11
|
+
controller_class ||= described_class
|
12
|
+
controller_path = controller_class.controller_path
|
13
|
+
Wallaby::TestUtils.draw(routes, controller_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
context.after { Rails.application.reload_routes! }
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param routes
|
20
|
+
# @param controller_path [String]
|
21
|
+
def draw(routes, controller_path)
|
22
|
+
routes.draw do
|
23
|
+
get ':resources', to: "#{controller_path}#index", as: :resources
|
24
|
+
get ':resources/:id', to: "#{controller_path}#show", as: :resource
|
25
|
+
get ':resources/new', to: "#{controller_path}#new"
|
26
|
+
get ':resources/:id/edit', to: "#{controller_path}#edit"
|
27
|
+
post ':resources', to: "#{controller_path}#create"
|
28
|
+
patch ':resources/:id', to: "#{controller_path}#update"
|
29
|
+
delete ':resources/:id', to: "#{controller_path}#destroy"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|