wallaby-core 0.1.2 → 0.2.3

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +60 -13
  3. data/app/controllers/wallaby/resources_controller.rb +15 -374
  4. data/app/security/ability.rb +1 -1
  5. data/config/locales/wallaby.en.yml +92 -128
  6. data/config/locales/wallaby_class.en.yml +2 -23
  7. data/lib/adaptors/wallaby/custom/default_provider.rb +1 -1
  8. data/lib/adaptors/wallaby/custom/model_decorator.rb +8 -7
  9. data/lib/adaptors/wallaby/custom/model_finder.rb +3 -2
  10. data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +1 -1
  11. data/lib/adaptors/wallaby/custom/model_service_provider.rb +1 -40
  12. data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +30 -24
  13. data/lib/authorizers/wallaby/default_authorization_provider.rb +6 -13
  14. data/lib/authorizers/wallaby/model_authorizer.rb +43 -67
  15. data/lib/authorizers/wallaby/pundit_authorization_provider.rb +21 -30
  16. data/lib/concerns/wallaby/application_concern.rb +110 -0
  17. data/lib/concerns/wallaby/authentication_concern.rb +162 -0
  18. data/lib/concerns/wallaby/authorizable.rb +8 -14
  19. data/lib/concerns/wallaby/baseable.rb +91 -10
  20. data/lib/concerns/wallaby/decoratable.rb +3 -3
  21. data/lib/concerns/wallaby/engineable.rb +1 -1
  22. data/lib/concerns/wallaby/fieldable.rb +4 -4
  23. data/lib/concerns/wallaby/paginatable.rb +3 -3
  24. data/lib/concerns/wallaby/prefixable.rb +21 -0
  25. data/lib/concerns/wallaby/resourcable.rb +4 -35
  26. data/lib/concerns/wallaby/resources_concern.rb +434 -0
  27. data/lib/concerns/wallaby/servicable.rb +4 -10
  28. data/lib/decorators/wallaby/resource_decorator.rb +53 -80
  29. data/lib/errors/wallaby/{cell_handling.rb → class_not_found.rb} +1 -1
  30. data/lib/errors/wallaby/model_not_found.rb +3 -1
  31. data/lib/errors/wallaby/resource_not_found.rb +1 -1
  32. data/lib/helpers/wallaby/application_helper.rb +6 -9
  33. data/lib/helpers/wallaby/form_helper.rb +2 -9
  34. data/lib/helpers/wallaby/index_helper.rb +2 -14
  35. data/lib/helpers/wallaby/links_helper.rb +5 -5
  36. data/lib/helpers/wallaby/resources_helper.rb +3 -7
  37. data/lib/helpers/wallaby/secure_helper.rb +3 -3
  38. data/lib/helpers/wallaby/styling_helper.rb +17 -3
  39. data/lib/interfaces/wallaby/mode.rb +5 -5
  40. data/lib/interfaces/wallaby/model_authorization_provider.rb +15 -13
  41. data/lib/interfaces/wallaby/model_decorator.rb +15 -3
  42. data/lib/paginators/wallaby/model_paginator.rb +14 -45
  43. data/lib/parsers/wallaby/parser.rb +49 -14
  44. data/lib/routes/wallaby/resources_router.rb +1 -1
  45. data/lib/servicers/wallaby/model_servicer.rb +32 -62
  46. data/lib/services/wallaby/map/mode_mapper.rb +14 -14
  47. data/lib/services/wallaby/map/model_class_collector.rb +2 -2
  48. data/lib/services/wallaby/map/model_class_mapper.rb +7 -26
  49. data/lib/services/wallaby/prefixes_builder.rb +15 -49
  50. data/lib/services/wallaby/type_renderer.rb +3 -13
  51. data/lib/utils/wallaby/locale.rb +53 -0
  52. data/lib/utils/wallaby/model_utils.rb +4 -3
  53. data/lib/utils/wallaby/module_utils.rb +1 -1
  54. data/lib/utils/wallaby/utils.rb +10 -15
  55. data/lib/wallaby/class_array.rb +75 -0
  56. data/lib/wallaby/class_hash.rb +94 -0
  57. data/lib/wallaby/classifier.rb +29 -0
  58. data/lib/wallaby/configuration/mapping.rb +33 -27
  59. data/lib/wallaby/configuration/metadata.rb +1 -1
  60. data/lib/wallaby/configuration/models.rb +5 -9
  61. data/lib/wallaby/configuration/security.rb +6 -3
  62. data/lib/wallaby/configuration/sorting.rb +1 -1
  63. data/lib/wallaby/configuration.rb +31 -2
  64. data/lib/wallaby/constants.rb +10 -8
  65. data/lib/wallaby/core/version.rb +1 -1
  66. data/lib/wallaby/core.rb +21 -16
  67. data/lib/wallaby/engine.rb +9 -20
  68. data/lib/wallaby/logger.rb +35 -0
  69. data/lib/wallaby/map.rb +20 -17
  70. data/lib/wallaby/preloader.rb +77 -0
  71. metadata +48 -22
  72. data/app/controllers/wallaby/application_controller.rb +0 -84
  73. data/app/controllers/wallaby/secure_controller.rb +0 -81
  74. data/lib/concerns/wallaby/rails_overridden_methods.rb +0 -42
  75. data/lib/concerns/wallaby/themeable.rb +0 -40
  76. data/lib/paginators/wallaby/resource_paginator.rb +0 -12
  77. data/lib/renderers/wallaby/cell.rb +0 -137
  78. data/lib/renderers/wallaby/cell_resolver.rb +0 -89
  79. data/lib/renderers/wallaby/custom_lookup_context.rb +0 -64
  80. data/lib/renderers/wallaby/custom_partial_renderer.rb +0 -33
  81. data/lib/renderers/wallaby/custom_renderer.rb +0 -16
  82. data/lib/utils/wallaby/cell_utils.rb +0 -34
  83. data/lib/utils/wallaby/preload_utils.rb +0 -44
@@ -1,45 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wallaby
4
- # Model servicer contains resourceful operations for Rails resourceful actions.
4
+ # This is the base servicer class to provider data source related operations
5
+ # for given/associated model. In general, it works together with {#authorizer}
6
+ # to ensure that all operations are legitmate.
7
+ #
8
+ # For best practice, please create an application servicer class (see example)
9
+ # to better control the functions shared between different model servicers.
10
+ # @example Create an application class for Admin Interface usage
11
+ # class Admin::ApplicationServicer < Wallaby::ModelServicer
12
+ # base_class!
13
+ # end
5
14
  class ModelServicer
6
15
  extend Baseable::ClassMethods
7
-
8
- class << self
9
- # @!attribute [w] model_class
10
- attr_writer :model_class
11
-
12
- # @!attribute [r] model_class
13
- # Return associated model class, e.g. return **Product** for **ProductServicer**.
14
- #
15
- # If Wallaby can't recognise the model class for Servicer, it's required to be configured as below example:
16
- # @example To configure model class
17
- # class Admin::ProductServicer < Admin::ApplicationServicer
18
- # self.model_class = Product
19
- # end
20
- # @example To configure model class for version below 5.2.0
21
- # class Admin::ProductServicer < Admin::ApplicationServicer
22
- # def self.model_class
23
- # Product
24
- # end
25
- # end
26
- # @return [Class] assoicated model class
27
- # @return [nil] if current class is marked as base class
28
- # @return [nil] if current class is the same as the value of {Wallaby::Configuration::Mapping#model_servicer}
29
- # @return [nil] if current class is {Wallaby::ModelServicer}
30
- # @return [nil] if assoicated model class is not found
31
- def model_class
32
- return unless self < ModelServicer
33
- return if base_class? || self == Wallaby.configuration.mapping.model_servicer
34
-
35
- @model_class ||= Map.model_class_map(name.gsub(/(^#{namespace}::)|(Servicer$)/, EMPTY_STRING))
36
- end
37
-
38
- # @!attribute provider_class
39
- # @return [Class] service provider class
40
- # @since 5.2.0
41
- attr_accessor :provider_class
42
- end
16
+ base_class!
43
17
 
44
18
  # @!attribute [r] model_class
45
19
  # @return [Class]
@@ -47,46 +21,41 @@ module Wallaby
47
21
 
48
22
  # @!attribute [r] model_decorator
49
23
  # @return [Wallaby::ModelDecorator]
50
- # @since 5.2.0
24
+ # @since wallaby-5.2.0
51
25
  attr_reader :model_decorator
52
26
 
53
27
  # @!attribute [r] authorizer
54
28
  # @return [Wallaby::ModelAuthorizer]
55
- # @since 5.2.0
29
+ # @since wallaby-5.2.0
56
30
  attr_reader :authorizer
57
31
 
58
32
  # @!attribute [r] provider
59
- # @return [Wallaby::ModelServiceProvider]
60
- # @since 5.2.0
33
+ # @return [Wallaby::ModelServiceProvider] the instance that does the job
34
+ # @since wallaby-5.2.0
61
35
  attr_reader :provider
62
36
 
63
37
  # @!method user
64
38
  # @return [Object]
65
- # @since 5.2.0
39
+ # @since wallaby-5.2.0
66
40
  delegate :user, to: :authorizer
67
41
 
68
- # During initialization, Wallaby will assign a service provider for this servicer
69
- # to carry out the actual execution.
70
- #
71
- # Therefore, all its actions can be completely replaced by user's own implemnetation.
72
42
  # @param model_class [Class]
73
43
  # @param authorizer [Wallaby::ModelAuthorizer]
74
44
  # @param model_decorator [Wallaby::ModelDecorator]
75
- # @raise [ArgumentError] if param model_class is blank
45
+ # @raise [ArgumentError] if model_class is blank
76
46
  def initialize(model_class, authorizer, model_decorator = nil)
77
47
  @model_class = model_class || self.class.model_class
78
- raise ArgumentError, I18n.t('errors.required', subject: 'model_class') unless @model_class
48
+ raise ArgumentError, 'Please provide a `model_class`.' unless @model_class
79
49
 
80
50
  @model_decorator = model_decorator || Map.model_decorator_map(model_class)
81
51
  @authorizer = authorizer
82
- provider_class = self.class.provider_class || Map.service_provider_map(@model_class)
83
- @provider = provider_class.new(@model_class, @model_decorator)
52
+ @provider = Map.service_provider_map(@model_class).new(@model_class, @model_decorator)
84
53
  end
85
54
 
86
55
  # @note This is a template method that can be overridden by subclasses.
87
56
  # Whitelist parameters for mass assignment.
88
57
  # @param params [ActionController::Parameters, Hash]
89
- # @param action [String, Symbol]
58
+ # @param action [String, Symbol, nil]
90
59
  # @return [ActionController::Parameters] permitted params
91
60
  def permit(params, action = nil)
92
61
  provider.permit params, action, authorizer
@@ -95,58 +64,59 @@ module Wallaby
95
64
  # @note This is a template method that can be overridden by subclasses.
96
65
  # Return a collection by querying the datasource (e.g. database, REST API).
97
66
  # @param params [ActionController::Parameters, Hash]
98
- # @return [Enumerable] list of records
67
+ # @return [Enumerable] list of resources
99
68
  def collection(params)
100
69
  provider.collection params, authorizer
101
70
  end
102
71
 
72
+ # @!method paginate(query, params)
103
73
  # @note This is a template method that can be overridden by subclasses.
104
74
  # Paginate given {#collection}.
105
75
  # @param query [Enumerable]
106
76
  # @param params [ActionController::Parameters]
107
- # @return [Enumerable] list of records
77
+ # @return [Enumerable] list of resources
108
78
  delegate :paginate, to: :provider
109
79
 
110
80
  # @note This is a template method that can be overridden by subclasses.
111
81
  # Initialize an instance of the model class.
112
82
  # @param params [ActionController::Parameters]
113
- # @return [Object] initialized object
83
+ # @return [Object] initialized resource
114
84
  def new(params)
115
85
  provider.new params, authorizer
116
86
  end
117
87
 
118
88
  # @note This is a template method that can be overridden by subclasses.
119
- # To find a record.
89
+ # To find a resource.
120
90
  # @param id [Object]
121
91
  # @param params [ActionController::Parameters]
122
- # @return [Object] resource object
92
+ # @return [Object] found resource
123
93
  def find(id, params)
124
94
  provider.find id, params, authorizer
125
95
  end
126
96
 
127
97
  # @note This is a template method that can be overridden by subclasses.
128
- # To create a record.
98
+ # To create a resource.
129
99
  # @param resource [Object]
130
100
  # @param params [ActionController::Parameters]
131
- # @return [Object] resource object
101
+ # @return [Object] created resource
132
102
  def create(resource, params)
133
103
  provider.create resource, params, authorizer
134
104
  end
135
105
 
136
106
  # @note This is a template method that can be overridden by subclasses.
137
- # To update a record.
107
+ # To update a resource.
138
108
  # @param resource [Object]
139
109
  # @param params [ActionController::Parameters]
140
- # @return [Object] resource object
110
+ # @return [Object] resource
141
111
  def update(resource, params)
142
112
  provider.update resource, params, authorizer
143
113
  end
144
114
 
145
115
  # @note This is a template method that can be overridden by subclasses.
146
- # To delete a record.
116
+ # To delete a resource.
147
117
  # @param resource [Object]
148
118
  # @param params [ActionController::Parameters]
149
- # @return [Object] resource object
119
+ # @return [Object] resource
150
120
  def destroy(resource, params)
151
121
  provider.destroy resource, params, authorizer
152
122
  end
@@ -2,23 +2,23 @@
2
2
 
3
3
  module Wallaby
4
4
  class Map
5
- # To generate a hash map (`model` => `mode`).
6
- # This will be used to tell if a model can be handled by Wallaby
5
+ # Go through each {Wallaby::Mode} (e.g. **ActiveRecord**/**Her**)
6
+ # and find out all the model classes respectively.
7
+ # Then a hash (Model => {Wallaby::Mode}) is constructed
8
+ # to tell {Wallaby} which {Wallaby::Mode} to use for a given model.
7
9
  class ModeMapper
8
- # @param mode_classes [Array<Class>] model classes
9
- def initialize(mode_classes)
10
- @mode_classes = mode_classes
11
- end
10
+ extend Classifier
12
11
 
13
- # This will walk through each mode (e.g. **ActiveRecord**/**Her**) then pull out all the models,
14
- # and then form a hash of (`model` => `mode`).
15
- # @return [Hash] { model_class => mode }
16
- def map
17
- return {} if @mode_classes.blank?
12
+ # @param class_names [Wallaby::ClassArray] mode class names
13
+ # @return [WallabyClassHash]
14
+ def self.execute(class_names)
15
+ ClassHash.new.tap do |hash|
16
+ next if class_names.blank?
18
17
 
19
- @mode_classes.each_with_object({}) do |mode_class, map|
20
- mode_class.model_finder.new.all.each do |model_class|
21
- map[model_class] = mode_class
18
+ class_names.each_with_object(hash) do |mode_name, map|
19
+ mode_name.model_finder.new.all.each do |model_class|
20
+ map[model_class] = mode_name
21
+ end
22
22
  end
23
23
  end
24
24
  end
@@ -8,7 +8,7 @@ module Wallaby
8
8
  # @param models [Array<Class>]
9
9
  def initialize(configuration, models = nil)
10
10
  @configuration = configuration
11
- @models = models || []
11
+ @models = ClassArray.new(models || [])
12
12
  end
13
13
 
14
14
  # @return [Array<Class>] model class
@@ -26,7 +26,7 @@ module Wallaby
26
26
  invalid_models = configured_models - @models
27
27
  return if invalid_models.blank?
28
28
 
29
- message = I18n.t 'errors.invalid.models', models: invalid_models.to_sentence
29
+ message = Locale.t 'errors.invalid.models', models: invalid_models.to_sentence
30
30
  raise InvalidError, message
31
31
  end
32
32
 
@@ -2,37 +2,18 @@
2
2
 
3
3
  module Wallaby
4
4
  class Map
5
- # Generate a map.
5
+ # Go through the class list and generate a {.map .map} that uses the class's model_class as the key.
6
6
  class ModelClassMapper
7
- # Iterate all classes and generate a hash using their model classes as the key
8
- # @see #map
9
7
  # @param class_array [Array<Class>]
10
- # @return [Hash] model class => descendant class
11
- def self.map(class_array, &block)
12
- new.send :map, class_array, &block
13
- end
14
-
15
- protected
8
+ # @return [Wallaby::ClassHash] model class => descendant class
9
+ def self.map(class_array)
10
+ (class_array || EMPTY_ARRAY).each_with_object(ClassHash.new) do |klass, hash|
11
+ next if ModuleUtils.anonymous_class?(klass)
12
+ next if klass.try(:base_class?) || klass.model_class.blank?
16
13
 
17
- # @return [Hash] model class => descendant class
18
- def map(class_array)
19
- (class_array || EMPTY_ARRAY).each_with_object({}) do |klass, map|
20
- next if anonymous?(klass) || base_class?(klass) || !klass.model_class
21
-
22
- map[klass.model_class] = block_given? ? yield(klass) : klass
14
+ hash[klass.model_class] = block_given? ? yield(klass) : klass
23
15
  end
24
16
  end
25
-
26
- # @see Wallaby::ModuleUtils.anonymous_class?
27
- def anonymous?(klass)
28
- ModuleUtils.anonymous_class? klass
29
- end
30
-
31
- # @param klass [Class]
32
- # @return [Boolean] whether the class is base or not
33
- def base_class?(klass)
34
- ModuleUtils.try_to klass, :base_class?
35
- end
36
17
  end
37
18
  end
38
19
  end
@@ -3,64 +3,30 @@
3
3
  module Wallaby
4
4
  # To extend prefixes to provide more possibility
5
5
  class PrefixesBuilder
6
- # @param origin_prefixes [Array<string>] a list of all the origin prefixes
7
- # @param action_name [String] action name
8
- # @param resources_name [String] resources name
9
- # @param script_name [String] script name
10
- # @param theme_name [String] theme name
11
- def self.build(origin_prefixes:, action_name:, resources_name:, script_name:, theme_name:)
12
- new(
13
- origin_prefixes: origin_prefixes,
14
- action_name: action_name,
15
- resources_name: resources_name,
16
- script_name: script_name,
17
- theme_name: theme_name
18
- ).send :build
19
- end
6
+ include ActiveModel::Model
20
7
 
21
- private
8
+ attr_accessor :prefixes
9
+ attr_accessor :resources_name
10
+ attr_accessor :script_name
22
11
 
23
- # Constructor
24
- def initialize(origin_prefixes:, action_name:, resources_name:, script_name:, theme_name:)
25
- @origin_prefixes = origin_prefixes
26
- @action_name = action_name
27
- @resources_name = resources_name
28
- @script_name = script_name
29
- @theme_name = theme_name
30
- end
12
+ def execute
13
+ return if prefixes.include? resources_path
31
14
 
32
- # @return [Array<String>] prefixes
33
- def build
34
- prefixes = minimal_prefixes
35
- prefixes.unshift mounted_prefix unless prefixes.include? resources_path
36
- prefixes.uniq.compact.each_with_object([]) do |prefix, result|
37
- result << "#{prefix}/#{suffix}" << prefix
38
- end
39
- end
15
+ full_prefix = [script_path, resources_path].compact.join(SLASH)
40
16
 
41
- # @return [Array<String>] prefixes starting from wallaby controller path
42
- def minimal_prefixes
43
- index = @origin_prefixes.index ResourcesController.controller_path
44
- @origin_prefixes.slice(0..index).tap do |prefixes|
45
- insert_index = prefixes.length > 1 ? -2 : 0
46
- prefixes.insert insert_index, @theme_name if @theme_name.present?
47
- end
48
- end
17
+ return if prefixes.include? full_prefix
49
18
 
50
- # @return [String] a prefix of the mouted path
51
- def mounted_prefix
52
- prefix = (@script_name || '').sub(%r{^/}, '')
53
- prefix << SLASH if prefix.present?
54
- prefix << resources_path if resources_path
19
+ prefixes.insert 0, full_prefix
55
20
  end
56
21
 
57
- # @return [String]
58
- def suffix
59
- @suffix ||= CellUtils.to_action_prefix @action_name
60
- end
22
+ private
61
23
 
62
24
  def resources_path
63
- @resources_path ||= @resources_name.try :gsub, COLONS, SLASH
25
+ @resources_path ||= resources_name.try :gsub, COLONS, SLASH
26
+ end
27
+
28
+ def script_path
29
+ @script_path ||= script_name.try :[], 1..-1
64
30
  end
65
31
  end
66
32
  end
@@ -23,28 +23,18 @@ module Wallaby
23
23
  # @raise [ArgumentError] if field_name is not provided
24
24
  # @raise [ArgumentError] if object is not decorated
25
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?
26
+ raise ArgumentError, Locale.t('errors.required', subject: 'form') if locals.key?(:form) && locals[:form].blank?
27
+ raise ArgumentError, Locale.t('errors.required', subject: 'field_name') if locals[:field_name].blank?
28
28
  raise ArgumentError, 'Object is not decorated.' unless locals[:object].is_a? ResourceDecorator
29
29
  end
30
30
 
31
31
  # @param locals [Hash]
32
32
  # @param action [String]
33
33
  def complete(locals, action)
34
- action_name = CellUtils.to_action_prefix action
34
+ action_name = FORM_ACTIONS[action] || action
35
35
  locals[:metadata] = locals[:object].public_send :"#{action_name}_metadata_of", locals[:field_name]
36
36
  locals[:value] = locals[:object].public_send locals[:field_name]
37
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
38
  end
49
39
  end
50
40
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Locale related
5
+ module Locale
6
+ class << self
7
+ # Extend translation just for Wallaby
8
+ # so that translation can be prefixed with `wallaby.`
9
+ # @param key [String, Symbol, Array]
10
+ # @param options [Hash] the rest of the arguments
11
+ # @return [String] translation
12
+ def t(key, options = {})
13
+ translator = options.delete(:translator) || I18n.method(:t)
14
+ return translator.call(key, options) unless key.is_a?(String) || key.is_a?(Symbol)
15
+
16
+ new_key, new_defaults = normalize key, options.delete(:default)
17
+
18
+ translator.call(new_key, { default: new_defaults }.merge(options))
19
+ end
20
+
21
+ private
22
+
23
+ # @param key [String, Symbol, Array]
24
+ # @param defaults [String, Symbol, Array]
25
+ # @return [Array]
26
+ def normalize(key, defaults)
27
+ *keys, default = *defaults
28
+
29
+ # default will NOT be considered as one of the key
30
+ # if it is not set or if it is a String (since String means translation for I18n.t)
31
+ unless default.nil? || default.is_a?(String)
32
+ keys << default
33
+ default = nil
34
+ end
35
+
36
+ new_defaults = prefix_defaults_from keys.unshift(key)
37
+ new_key = new_defaults.shift
38
+ new_defaults << default if default
39
+ [new_key, new_defaults]
40
+ end
41
+
42
+ # Duplicate and prefix the keys respectively
43
+ # @param keys [Array]
44
+ # @return [Array] new_keys
45
+ def prefix_defaults_from(keys)
46
+ keys.each_with_object([]) do |k, result|
47
+ result << :"wallaby.#{k}" unless k.to_s.start_with? 'wallaby.'
48
+ result << k.to_sym
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wallaby
4
- # Utils for model
4
+ # Model related utils
5
5
  module ModelUtils
6
6
  class << self
7
7
  # Convert model class (e.g. `Namespace::Product`) into resources name (e.g. `namespace::products`)
@@ -32,10 +32,11 @@ module Wallaby
32
32
  return if resources_name.blank?
33
33
 
34
34
  class_name = to_model_name resources_name
35
+ # NOTE: DO NOT try to use const_defined? and const_get EVER.
36
+ # This is Rails, use constantize
35
37
  class_name.constantize
36
38
  rescue NameError
37
- Rails.logger.warn I18n.t('errors.not_found.model', model: class_name)
38
- nil
39
+ Logger.warn Locale.t('errors.not_found.model', model: class_name), sourcing: 2..10
39
40
  end
40
41
 
41
42
  # Convert resources name (e.g. `namespace::products`) into model name (e.g. `Namespace::Product`)
@@ -32,7 +32,7 @@ module Wallaby
32
32
  return unless child && parent
33
33
  return if child < parent
34
34
 
35
- raise ::ArgumentError, I18n.t('errors.invalid.inheritance', klass: child, parent: parent)
35
+ raise ::ArgumentError, Locale.t('errors.invalid.inheritance', klass: child, parent: parent)
36
36
  end
37
37
 
38
38
  # If block is given, run the block. Otherwise, return subject
@@ -3,25 +3,20 @@
3
3
  module Wallaby
4
4
  # Utils
5
5
  module Utils
6
- # Display deprecate message including the line where it's used
7
- # @param key [String]
8
- # @param caller [String] the line where it's called
9
- # @param options [Hash]
10
- def self.deprecate(key, caller:, options: {})
11
- warn I18n.t(key, options.merge(from: caller[0]))
12
- end
13
-
14
- # @deprecated Use {Wallaby::FilterUtils.filter_name_by} instead. It will be removed from 5.3.*
15
- def self.find_filter_name(filter_name, filters)
16
- deprecate 'deprecation.find_filter_name', caller: caller
17
- FilterUtils.filter_name_by filter_name, filters
18
- end
19
-
20
6
  # @see http://stackoverflow.com/a/8710663/1326499
21
7
  # @param object [Object]
22
8
  # @return [Object] a clone object
23
9
  def self.clone(object)
24
- ::Marshal.load(::Marshal.dump(object))
10
+ object.try(:deep_dup) || object && ::Marshal.load(::Marshal.dump(object))
11
+ end
12
+
13
+ # @param object [Object, nil]
14
+ # @return [String] inspection string for the given object
15
+ def self.inspect(object)
16
+ return 'nil' unless object
17
+ return object.name if object.is_a? Class
18
+
19
+ "#{object.class}##{object.id}"
25
20
  end
26
21
  end
27
22
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # This is a constant-safe array that stores Class value as String.
5
+ class ClassArray
6
+ include Classifier
7
+
8
+ # @param [Array] array
9
+ def initialize(array = [])
10
+ @internal = array || []
11
+ return if @internal.blank?
12
+
13
+ @internal.map!(&method(:to_class_name)).compact!
14
+ end
15
+
16
+ # @!attribute [r] internal
17
+ # @return [Array] The array to store Class values as String.
18
+ attr_reader :internal
19
+
20
+ # @!attribute [r] origin
21
+ # @return [Array] The original array.
22
+ def origin
23
+ # NOTE: DO NOT cache it by using instance variable!
24
+ @internal.map(&method(:to_class)).compact
25
+ end
26
+
27
+ # Save the value to the {#internal} array at the given index, and convert the Class value to String
28
+ def []=(index, value)
29
+ @internal[index] = to_class_name value
30
+ end
31
+
32
+ # Return the value for the given index
33
+ def [](index)
34
+ to_class @internal[index]
35
+ end
36
+
37
+ # @param other [Array]
38
+ # @return [Wallaby::ClassArray] new Class array
39
+ def concat(other)
40
+ self.class.new origin.concat(other.try(:origin) || other)
41
+ end
42
+
43
+ # @param other [Array]
44
+ # @return [Wallaby::ClassArray] new Class array
45
+ def -(other)
46
+ self.class.new origin - (other.try(:origin) || other)
47
+ end
48
+
49
+ # @return [Wallaby::ClassArray] self
50
+ def each(&block)
51
+ origin.each(&block)
52
+ self
53
+ end
54
+
55
+ # @!method ==(other)
56
+ # Compare #{origin} with other.
57
+ delegate :==, to: :origin
58
+
59
+ # @!method blank?
60
+ delegate :blank?, to: :internal
61
+
62
+ # @!method each_with_object(object)
63
+ delegate :each_with_object, to: :origin
64
+
65
+ # @!method to_sentence
66
+ delegate :to_sentence, to: :origin
67
+
68
+ # Ensure to freeze the {#internal}
69
+ # @return [Wallaby::ClassArray] self
70
+ def freeze
71
+ @internal.freeze
72
+ super
73
+ end
74
+ end
75
+ end