wallaby-core 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/controllers/wallaby/resources_controller.rb +10 -1
  4. data/config/locales/wallaby_class.en.yml +2 -2
  5. data/lib/adaptors/wallaby/custom/default_provider.rb +1 -1
  6. data/lib/adaptors/wallaby/custom/model_decorator.rb +8 -7
  7. data/lib/adaptors/wallaby/custom/model_finder.rb +3 -2
  8. data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +1 -1
  9. data/lib/adaptors/wallaby/custom/model_service_provider.rb +1 -40
  10. data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +29 -24
  11. data/lib/authorizers/wallaby/default_authorization_provider.rb +6 -13
  12. data/lib/authorizers/wallaby/model_authorizer.rb +43 -67
  13. data/lib/authorizers/wallaby/pundit_authorization_provider.rb +21 -30
  14. data/lib/concerns/wallaby/application_concern.rb +1 -2
  15. data/lib/concerns/wallaby/authentication_concern.rb +74 -5
  16. data/lib/concerns/wallaby/authorizable.rb +8 -8
  17. data/lib/concerns/wallaby/baseable.rb +91 -10
  18. data/lib/concerns/wallaby/decoratable.rb +3 -3
  19. data/lib/concerns/wallaby/engineable.rb +1 -1
  20. data/lib/concerns/wallaby/fieldable.rb +4 -4
  21. data/lib/concerns/wallaby/paginatable.rb +3 -3
  22. data/lib/concerns/wallaby/resourcable.rb +0 -35
  23. data/lib/concerns/wallaby/resources_concern.rb +3 -2
  24. data/lib/concerns/wallaby/servicable.rb +4 -4
  25. data/lib/decorators/wallaby/resource_decorator.rb +53 -80
  26. data/lib/errors/wallaby/class_not_found.rb +6 -0
  27. data/lib/errors/wallaby/model_not_found.rb +2 -0
  28. data/lib/helpers/wallaby/resources_helper.rb +3 -0
  29. data/lib/helpers/wallaby/secure_helper.rb +3 -3
  30. data/lib/interfaces/wallaby/mode.rb +3 -3
  31. data/lib/interfaces/wallaby/model_authorization_provider.rb +15 -13
  32. data/lib/interfaces/wallaby/model_decorator.rb +15 -3
  33. data/lib/paginators/wallaby/model_paginator.rb +14 -45
  34. data/lib/servicers/wallaby/model_servicer.rb +31 -62
  35. data/lib/services/wallaby/map/mode_mapper.rb +14 -14
  36. data/lib/services/wallaby/map/model_class_collector.rb +1 -1
  37. data/lib/services/wallaby/map/model_class_mapper.rb +7 -26
  38. data/lib/services/wallaby/type_renderer.rb +0 -10
  39. data/lib/utils/wallaby/model_utils.rb +4 -3
  40. data/lib/utils/wallaby/utils.rb +9 -8
  41. data/lib/wallaby/class_array.rb +75 -0
  42. data/lib/wallaby/class_hash.rb +94 -0
  43. data/lib/wallaby/classifier.rb +29 -0
  44. data/lib/wallaby/configuration.rb +31 -2
  45. data/lib/wallaby/configuration/mapping.rb +33 -21
  46. data/lib/wallaby/configuration/metadata.rb +1 -1
  47. data/lib/wallaby/configuration/models.rb +5 -9
  48. data/lib/wallaby/configuration/security.rb +6 -3
  49. data/lib/wallaby/configuration/sorting.rb +1 -1
  50. data/lib/wallaby/core.rb +13 -7
  51. data/lib/wallaby/core/version.rb +1 -1
  52. data/lib/wallaby/engine.rb +9 -20
  53. data/lib/wallaby/logger.rb +35 -0
  54. data/lib/wallaby/map.rb +20 -17
  55. data/lib/wallaby/preloader.rb +77 -0
  56. metadata +8 -4
  57. data/lib/utils/wallaby/logger.rb +0 -21
  58. data/lib/utils/wallaby/preload_utils.rb +0 -44
@@ -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
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # This is a constant-safe hash that stores Class key/value as String
5
+ # and returns value as Class if it was a Class.
6
+ #
7
+ # It can be used for global methods (e.g. {Wallaby::Map.mode_map}) which cache the computed result,
8
+ # so that when Rails reloads, it won't complain that old Class constants still exist in
9
+ # ObjectSpace (see https://github.com/wallaby-rails/wallaby/issues/181).
10
+ #
11
+ # ```
12
+ # A copy of SupportAdmin::ApplicationAuthorizer has been removed from the module tree but is still active!
13
+ # ```
14
+ #
15
+ # As there won't be any Class constants being stored, they will converted to String in {#internal} Hash.
16
+ class ClassHash
17
+ # @!attribute [r] internal
18
+ # @return [Hash] The hash to store Class keys/values as String.
19
+ attr_reader :internal
20
+
21
+ # @param [Hash] hash
22
+ def initialize(hash = {})
23
+ @internal =
24
+ (hash || {})
25
+ .transform_keys(&method(:to_class_name))
26
+ .transform_values(&method(:to_class_name))
27
+ end
28
+
29
+ # @!attribute [r] origin
30
+ # @return [Hash] The original hash.
31
+ def origin
32
+ # NOTE: DO NOT cache it by using instance variable!
33
+ @internal
34
+ .transform_keys(&method(:to_class))
35
+ .transform_values(&method(:to_class))
36
+ .reject { |k, v| k.nil? || v.nil? }
37
+ end
38
+
39
+ # @!method keys
40
+ # Return the keys of {#origin}.
41
+ delegate :keys, to: :origin
42
+
43
+ # @!method values
44
+ # Return the values of {#origin}.
45
+ delegate :values, to: :origin
46
+
47
+ # @!method ==(other)
48
+ # Compare #{origin} with other.
49
+ delegate :==, to: :origin
50
+
51
+ # Save the key/value to the {#internal} hash, and convert the Class key/value to String
52
+ def []=(key, value)
53
+ @internal[to_class_name(key)] = to_class_name(value)
54
+ end
55
+
56
+ # Return the value for the given key, and convert the value back to Class if it was a Class
57
+ def [](key)
58
+ to_class @internal[to_class_name(key)]
59
+ end
60
+
61
+ # @param other [Hash]
62
+ # @return [Wallaby::ClassHash] new Class hash
63
+ def merge(other)
64
+ self.class.new origin.merge(other.try(:origin) || other)
65
+ end
66
+
67
+ # @return [Wallaby::ClassHash] new Class hash
68
+ def select(&block)
69
+ self.class.new origin.select(&block)
70
+ end
71
+
72
+ # Ensure to freeze the {#internal}
73
+ # @return [Wallaby::ClassHash] self
74
+ def freeze
75
+ @internal.freeze
76
+ super
77
+ end
78
+
79
+ protected
80
+
81
+ # Convert to Class name
82
+ def to_class_name(klass)
83
+ klass.is_a?(Class) ? [klass.name, true] : [klass, false]
84
+ end
85
+
86
+ # Convert to Class
87
+ def to_class(pair)
88
+ val, is_class = pair
89
+ is_class ? val.constantize : val
90
+ rescue NameError
91
+ Logger.error "`#{val}` is not a valid Class name."
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Concern to handle the conversion between Class and String
5
+ module Classifier
6
+ # Convert Class to String. If not Class, unchanged.
7
+ # @param klass [Object]
8
+ # @return [String] if klass is a Class
9
+ # @return [Object] if klass is not a Class
10
+ def to_class_name(klass)
11
+ klass.try(:name) || klass || nil
12
+ end
13
+
14
+ # Convert String to Class. If not String, unchanged.
15
+ # @param name [Object]
16
+ # @return [Class] if name is a Class
17
+ # @return [Object] if name is not a String
18
+ # @return [nil] if class cannot be found
19
+ def to_class(name)
20
+ return name unless name.is_a? String
21
+
22
+ # NOTE: DO NOT try to use const_defined? and const_get EVER.
23
+ # This is Rails, use constantize
24
+ name.constantize
25
+ rescue NameError
26
+ Logger.error "`#{name}` is not a valid Class name."
27
+ end
28
+ end
29
+ end
@@ -4,8 +4,37 @@
4
4
  module Wallaby
5
5
  # Global configuration
6
6
  class Configuration
7
+ include Classifier
8
+
9
+ # @!attribute [w] model_paths
10
+ def model_paths=(*model_paths)
11
+ @model_paths =
12
+ model_paths.flatten.compact.presence.try do |paths|
13
+ next paths if paths.all? { |p| p.is_a?(String) }
14
+
15
+ raise(
16
+ ArgumentError,
17
+ 'Please provide a list of string paths, e.g. `["app/models", "app/core"]`'
18
+ )
19
+ end
20
+ end
21
+
22
+ # @!attribute [r] model_paths
23
+ # To configure the model folders that {Wallaby::Preloader} needs to load before everything else.
24
+ # @example To set the model paths
25
+ # Wallaby.config do |config|
26
+ # config.model_paths = ["app/models", "app/core"]
27
+ # end
28
+ # @return [Array<String>] model paths
29
+ # @since 0.2.2
30
+ def model_paths
31
+ @model_paths ||= %w(app/models)
32
+ end
33
+
7
34
  # @!attribute [w] base_controller
8
- attr_writer :base_controller
35
+ def base_controller=(base_controller)
36
+ @base_controller = to_class_name base_controller
37
+ end
9
38
 
10
39
  # @!attribute [r] base_controller
11
40
  # To globally configure the base controller class that {Wallaby::ApplicationController} should inherit from.
@@ -18,7 +47,7 @@ module Wallaby
18
47
  # end
19
48
  # @return [Class] base controller class
20
49
  def base_controller
21
- @base_controller ||= ::ApplicationController
50
+ to_class @base_controller ||= '::ApplicationController'
22
51
  end
23
52
 
24
53
  # @return [Wallaby::Configuration::Models] models configuration for custom mode
@@ -3,10 +3,14 @@
3
3
  module Wallaby
4
4
  class Configuration
5
5
  # Configuration used in {Wallaby::Map}
6
- # @since 5.1.6
6
+ # @since wallaby-5.1.6
7
7
  class Mapping
8
+ include Classifier
9
+
8
10
  # @!attribute [w] resources_controller
9
- attr_writer :resources_controller
11
+ def resources_controller=(resources_controller)
12
+ @resources_controller = to_class_name resources_controller
13
+ end
10
14
 
11
15
  # @!attribute [r] resources_controller
12
16
  # To globally configure the resources controller.
@@ -21,17 +25,19 @@ module Wallaby
21
25
  # config.mapping.resources_controller = ::GlobalResourcesController
22
26
  # end
23
27
  # @return [Class] resources controller class
24
- # @since 5.1.6
28
+ # @since wallaby-5.1.6
25
29
  def resources_controller
26
30
  @resources_controller ||=
27
31
  defined?(::Admin::ApplicationController) \
28
32
  && ::Admin::ApplicationController < ::Wallaby::ResourcesController \
29
- && ::Admin::ApplicationController
30
- @resources_controller ||= ResourcesController
33
+ && 'Admin::ApplicationController'
34
+ to_class @resources_controller ||= 'Wallaby::ResourcesController'
31
35
  end
32
36
 
33
37
  # @!attribute [w] resource_decorator
34
- attr_writer :resource_decorator
38
+ def resource_decorator=(resource_decorator)
39
+ @resource_decorator = to_class_name resource_decorator
40
+ end
35
41
 
36
42
  # @!attribute [r] resource_decorator
37
43
  # To globally configure the resource decorator.
@@ -46,17 +52,19 @@ module Wallaby
46
52
  # config.mapping.resource_decorator = ::GlobalResourceDecorator
47
53
  # end
48
54
  # @return [Class] resource decorator class
49
- # @since 5.1.6
55
+ # @since wallaby-5.1.6
50
56
  def resource_decorator
51
57
  @resource_decorator ||=
52
58
  defined?(::Admin::ApplicationDecorator) \
53
59
  && ::Admin::ApplicationDecorator < ::Wallaby::ResourceDecorator \
54
- && ::Admin::ApplicationDecorator
55
- @resource_decorator ||= ResourceDecorator
60
+ && 'Admin::ApplicationDecorator'
61
+ to_class @resource_decorator ||= 'Wallaby::ResourceDecorator'
56
62
  end
57
63
 
58
64
  # @!attribute [w] model_servicer
59
- attr_writer :model_servicer
65
+ def model_servicer=(model_servicer)
66
+ @model_servicer = to_class_name model_servicer
67
+ end
60
68
 
61
69
  # @!attribute [r] model_servicer
62
70
  # To globally configure the model servicer.
@@ -71,17 +79,19 @@ module Wallaby
71
79
  # config.mapping.model_servicer = ::GlobalModelServicer
72
80
  # end
73
81
  # @return [Class] model servicer class
74
- # @since 5.1.6
82
+ # @since wallaby-5.1.6
75
83
  def model_servicer
76
84
  @model_servicer ||=
77
85
  defined?(::Admin::ApplicationServicer) \
78
86
  && ::Admin::ApplicationServicer < ::Wallaby::ModelServicer \
79
- && ::Admin::ApplicationServicer
80
- @model_servicer ||= ModelServicer
87
+ && 'Admin::ApplicationServicer'
88
+ to_class @model_servicer ||= 'Wallaby::ModelServicer'
81
89
  end
82
90
 
83
91
  # @!attribute [w] model_authorizer
84
- attr_writer :model_authorizer
92
+ def model_authorizer=(model_authorizer)
93
+ @model_authorizer = to_class_name model_authorizer
94
+ end
85
95
 
86
96
  # @!attribute [r] model_authorizer
87
97
  # To globally configure the model authorizer.
@@ -96,17 +106,19 @@ module Wallaby
96
106
  # config.mapping.model_authorizer = ::GlobalModelAuthorizer
97
107
  # end
98
108
  # @return [Class] model authorizer class
99
- # @since 5.2.0
109
+ # @since wallaby-5.2.0
100
110
  def model_authorizer
101
111
  @model_authorizer ||=
102
112
  defined?(::Admin::ApplicationAuthorizer) \
103
113
  && ::Admin::ApplicationAuthorizer < ::Wallaby::ModelAuthorizer \
104
- && ::Admin::ApplicationAuthorizer
105
- @model_authorizer ||= ModelAuthorizer
114
+ && 'Admin::ApplicationAuthorizer'
115
+ to_class @model_authorizer ||= 'Wallaby::ModelAuthorizer'
106
116
  end
107
117
 
108
118
  # @!attribute [w] model_paginator
109
- attr_writer :model_paginator
119
+ def model_paginator=(model_paginator)
120
+ @model_paginator = to_class_name model_paginator
121
+ end
110
122
 
111
123
  # @!attribute [r] model_paginator
112
124
  # To globally configure the resource paginator.
@@ -121,13 +133,13 @@ module Wallaby
121
133
  # config.mapping.model_paginator = ::GlobalModelPaginator
122
134
  # end
123
135
  # @return [Class] resource paginator class
124
- # @since 5.2.0
136
+ # @since wallaby-5.2.0
125
137
  def model_paginator
126
138
  @model_paginator ||=
127
139
  defined?(::Admin::ApplicationPaginator) \
128
140
  && ::Admin::ApplicationPaginator < ::Wallaby::ModelPaginator \
129
- && ::Admin::ApplicationPaginator
130
- @model_paginator ||= ModelPaginator
141
+ && 'Admin::ApplicationPaginator'
142
+ to_class @model_paginator ||= 'Wallaby::ModelPaginator'
131
143
  end
132
144
  end
133
145
  end
@@ -14,7 +14,7 @@ module Wallaby
14
14
  # config.metadata.max = 50
15
15
  # end
16
16
  # @return [Integer] max number of characters to truncate, default to 20
17
- # @since 5.1.6
17
+ # @since wallaby-5.1.6
18
18
  def max
19
19
  @max ||= DEFAULT_MAX
20
20
  end
@@ -2,11 +2,7 @@
2
2
 
3
3
  module Wallaby
4
4
  class Configuration
5
- # @note In `development` environment, Rails recreates module/class constants on reload event.
6
- # If constants are cached/stored, they will become stale and Rails will raise conflicts.
7
- #
8
- # Hence, class name strings should be stored instead.
9
- # When classes are requested, strings will be constantized into classes.
5
+ # @deprecated will move this configuration to {Wallaby::ResourcesController} from 6.2
10
6
  # Models configuration to specify the model classes that Wallaby should handle.
11
7
  class Models
12
8
  # @note If models are whitelisted, models exclusion will NOT be applied.
@@ -17,12 +13,12 @@ module Wallaby
17
13
  # end
18
14
  # @param models [Array<Class, String>]
19
15
  def set(*models)
20
- @models = Array(models).flatten.map(&:to_s)
16
+ @models = ClassArray.new(models.flatten)
21
17
  end
22
18
 
23
19
  # @return [Array<Class>] the models configured
24
20
  def presence
25
- (@models ||= []).map(&:constantize)
21
+ @models ||= ClassArray.new # rubocop:disable Naming/MemoizedInstanceVariableName
26
22
  end
27
23
 
28
24
  # @note If models are whitelisted using {#set}, models exclusion will NOT be applied.
@@ -33,13 +29,13 @@ module Wallaby
33
29
  # end
34
30
  # @param models [Array<Class, String>]
35
31
  def exclude(*models)
36
- @excludes = Array(models).flatten.map(&:to_s)
32
+ @excludes = ClassArray.new(models.flatten)
37
33
  end
38
34
 
39
35
  # @return [Array<Class>] the list of models to exclude.
40
36
  # By default, `ActiveRecord::SchemaMigration` is excluded.
41
37
  def excludes
42
- (@excludes ||= ['ActiveRecord::SchemaMigration']).map(&:constantize)
38
+ @excludes ||= ClassArray.new ['ActiveRecord::SchemaMigration']
43
39
  end
44
40
  end
45
41
  end
@@ -3,6 +3,7 @@
3
3
  module Wallaby
4
4
  class Configuration
5
5
  # Security configuration
6
+ # TODO: remove this from 6.2
6
7
  class Security
7
8
  # Default block to return nil for current user
8
9
  DEFAULT_CURRENT_USER = -> { nil }
@@ -20,7 +21,7 @@ module Wallaby
20
21
  # Wallaby.config do |config|
21
22
  # config.security.logout_path = 'logout_path'
22
23
  # end
23
- # @since 5.1.4
24
+ # @since wallaby-5.1.4
24
25
  attr_accessor :logout_path
25
26
 
26
27
  # @!attribute logout_method
@@ -34,7 +35,7 @@ module Wallaby
34
35
  # Wallaby.config do |config|
35
36
  # config.security.logout_method = 'post'
36
37
  # end
37
- # @since 5.1.4
38
+ # @since wallaby-5.1.4
38
39
  attr_accessor :logout_method
39
40
 
40
41
  # @!attribute email_method
@@ -45,7 +46,7 @@ module Wallaby
45
46
  # Wallaby.config do |config|
46
47
  # config.security.email_method = 'email_address'
47
48
  # end
48
- # @since 5.1.4
49
+ # @since wallaby-5.1.4
49
50
  attr_accessor :email_method
50
51
 
51
52
  # To globally configure how to get user object.
@@ -57,6 +58,7 @@ module Wallaby
57
58
  # end
58
59
  # @yield A block to get user object. All application controller methods can be used in the block.
59
60
  def current_user(&block)
61
+ Logger.deprecated 'Wallaby will remove security.current_user? from 6.2.'
60
62
  if block_given?
61
63
  @current_user = block
62
64
  else
@@ -81,6 +83,7 @@ module Wallaby
81
83
  # end
82
84
  # @yield A block to authenticate user. All application controller methods can be used in the block.
83
85
  def authenticate(&block)
86
+ Logger.deprecated 'Wallaby will remove security.authenticate from 6.2.'
84
87
  if block_given?
85
88
  @authenticate = block
86
89
  else