wallaby-core 0.1.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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