wallaby-core 0.3.0.beta2 → 0.3.0
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.
- checksums.yaml +4 -4
- data/app/security/ability.rb +1 -1
- data/config/routes.rb +38 -24
- data/lib/adaptors/wallaby/custom/model_decorator.rb +3 -3
- data/lib/forms/wallaby/form_builder.rb +1 -1
- data/lib/interfaces/wallaby/model_decorator.rb +12 -11
- data/lib/routes/wallaby/id_regexp.rb +29 -0
- data/lib/routes/wallaby/lazy_regexp.rb +24 -0
- data/lib/routes/wallaby/resources_regexp.rb +26 -0
- data/lib/routes/wallaby/resources_router.rb +1 -1
- data/lib/utils/wallaby/inflector.rb +1 -1
- data/lib/wallaby/classifier.rb +16 -8
- data/lib/wallaby/configuration.rb +4 -0
- data/lib/wallaby/core/version.rb +1 -1
- data/lib/wallaby/core.rb +3 -0
- data/lib/wallaby/map.rb +12 -0
- data/lib/wallaby/preloader.rb +1 -0
- metadata +16 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78bd6d5518f084f9d968a6e880148186171a5d9e57155750d695c50a6cf40b70
|
4
|
+
data.tar.gz: b61387cb2a538b3befff1646adfdf2b9c207585b9bc0f4a42f56bb5e34465820
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce828c53a527a2dae0fe51aeb81e1a95d3282242f7b324de4f87542a6c670f90938612e0c263677cb3f2d68287fa182081a4a931762886d22467cdde0ec99d05
|
7
|
+
data.tar.gz: 5a18a775749c109e769d285d09d188c49f370faf13bde75e3a0ca7626ec31b95060b35fa5d4fd3a44b7438d433ca9f56b5b7966aa3bcbc01b43ae7d7256ef21a
|
data/app/security/ability.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# @!visibility private
|
4
|
-
#
|
4
|
+
# Default ability for {Wallaby}
|
5
5
|
# If main app has defined `ability.rb`, this file will not be loaded/used.
|
6
6
|
class Ability
|
7
7
|
include ::CanCan::Ability if defined?(::CanCan)
|
data/config/routes.rb
CHANGED
@@ -5,42 +5,56 @@ Wallaby::Engine.routes.draw do
|
|
5
5
|
# @see Wallaby::ApplicationConcern#healthy
|
6
6
|
get 'status', to: 'wallaby/resources#healthy'
|
7
7
|
|
8
|
-
with_options to: Wallaby::ResourcesRouter.new do
|
8
|
+
with_options to: Wallaby::ResourcesRouter.new do
|
9
9
|
# @see Wallaby::ResourcesConcern#home
|
10
|
-
|
10
|
+
root defaults: { action: 'home' }
|
11
11
|
|
12
12
|
# Error pages for all supported HTTP status in {Wallaby::ERRORS}
|
13
13
|
Wallaby::ERRORS.each do |status|
|
14
14
|
code = Rack::Utils::SYMBOL_TO_STATUS_CODE[status]
|
15
|
-
|
16
|
-
|
15
|
+
get status, defaults: { action: status.to_s }
|
16
|
+
get code.to_s, defaults: { action: status.to_s }
|
17
17
|
end
|
18
18
|
|
19
19
|
# resourceful routes.
|
20
20
|
#
|
21
|
-
#
|
22
|
-
#
|
21
|
+
# `*resources` param here will be converted to the model class
|
22
|
+
# used in the controller that [Wallaby::ResourcesRouter] dispatches to.
|
23
|
+
# For instance, `"order/items"` will become `Order::Item` later,
|
23
24
|
# and `Order::Item` will be used by servicer/authorizer/paginator through out the whole request process.
|
24
25
|
#
|
25
|
-
# Using colons in the `:resources` param e.g. `"order::items"` instead of `"order/items"` is
|
26
|
-
# to make nested namespace possible to be handled by these dynamic routes.
|
27
26
|
# @see Wallaby::ResourcesRouter
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
27
|
+
constraints = {
|
28
|
+
id: Wallaby::LazyRegexp.new(:id_regexp),
|
29
|
+
resources: Wallaby::LazyRegexp.new(:resources_regexp)
|
30
|
+
}
|
31
|
+
|
32
|
+
scope path: '*resources' do
|
33
|
+
with_options(constraints: constraints) do
|
34
|
+
# NOTE: DO NOT change the order of the following routes!!!
|
35
|
+
|
36
|
+
# Exact match for `*resources/new`
|
37
|
+
# @see Wallaby::ResourcesConcern#new
|
38
|
+
get 'new', defaults: { action: 'new' }, as: :new_resource
|
39
|
+
|
40
|
+
# Match `*resources`
|
41
|
+
# `''` needs to be before `':id'` so that the resourcesful route will match `orders/items` with:
|
42
|
+
# `resources: 'orders/items'` instead of `resources: 'orders', id: 'items'`
|
43
|
+
# @see Wallaby::ResourcesConcern#index
|
44
|
+
get '', defaults: { action: 'index' }, as: :resources
|
45
|
+
# @see Wallaby::ResourcesConcern#create
|
46
|
+
post '', defaults: { action: 'create' }
|
47
|
+
|
48
|
+
# Match `*resources/:id`
|
49
|
+
# @see Wallaby::ResourcesConcern#edit
|
50
|
+
get ':id/edit', defaults: { action: 'edit' }, as: :edit_resource
|
51
|
+
# @see Wallaby::ResourcesConcern#show
|
52
|
+
get ':id', defaults: { action: 'show' }, as: :resource
|
53
|
+
# @see Wallaby::ResourcesConcern#update
|
54
|
+
match ':id', via: %i[patch put], defaults: { action: 'update' }
|
55
|
+
# @see Wallaby::ResourcesConcern#destroy
|
56
|
+
delete ':id', defaults: { action: 'destroy' }
|
57
|
+
end
|
44
58
|
end
|
45
59
|
end
|
46
60
|
end
|
@@ -9,9 +9,9 @@ module Wallaby
|
|
9
9
|
def fields
|
10
10
|
@fields ||=
|
11
11
|
::ActiveSupport::HashWithIndifferentAccess.new.tap do |hash|
|
12
|
-
methods = model_class.public_instance_methods
|
12
|
+
methods = model_class.public_instance_methods.map(&:to_s)
|
13
13
|
methods
|
14
|
-
.grep(/[
|
14
|
+
.grep(/(\A[^!=]|[^!=]\Z)/).select { |method_id| methods.include? "#{method_id}=" }
|
15
15
|
.each { |attribute| hash[attribute] = { label: attribute.humanize, type: 'string' } }
|
16
16
|
end.freeze
|
17
17
|
end
|
@@ -45,7 +45,7 @@ module Wallaby
|
|
45
45
|
|
46
46
|
# @return [String, Symbole] default to `:id`
|
47
47
|
def primary_key
|
48
|
-
@primary_key ||= :id
|
48
|
+
@primary_key ||= fields.key?(:id) ? :id : fields.keys.first.try(:to_sym)
|
49
49
|
end
|
50
50
|
|
51
51
|
# @param resource [Object]
|
@@ -7,7 +7,7 @@ module Wallaby
|
|
7
7
|
include Fieldable
|
8
8
|
|
9
9
|
MISSING_METHODS_RELATED_TO_FIELDS =
|
10
|
-
/\A(?<
|
10
|
+
/\A(?<method_prefix>[a-zA-Z]\w*_)(?<method_suffix>fields=?|field_names=?|metadata_of|label_of|type_of)\Z/.freeze
|
11
11
|
|
12
12
|
# Initialize with model class
|
13
13
|
# @param model_class [Class]
|
@@ -123,7 +123,7 @@ module Wallaby
|
|
123
123
|
return super unless method_name.match?(MISSING_METHODS_RELATED_TO_FIELDS)
|
124
124
|
|
125
125
|
matched = MISSING_METHODS_RELATED_TO_FIELDS.match(method_name)
|
126
|
-
try("prefix_#{matched[:
|
126
|
+
try("prefix_#{matched[:method_suffix]}", *args, matched[:method_prefix], &block)
|
127
127
|
end
|
128
128
|
|
129
129
|
# Check if method looks like: `_fields`, `_field_names` that can be processed by {Fieldable}
|
@@ -150,19 +150,20 @@ module Wallaby
|
|
150
150
|
# @return [String, Symbol] type
|
151
151
|
# @raise [ArgumentError] when type is nil
|
152
152
|
def ensure_type_is_present(field_name, type, prefix = '')
|
153
|
-
type || raise(::ArgumentError, <<~INSTRUCTION
|
154
|
-
The
|
155
|
-
The possible causes are:
|
153
|
+
type || raise(::ArgumentError, <<~INSTRUCTION)
|
154
|
+
The field `#{field_name}` is missing its type definition. Potential causes include:
|
156
155
|
|
157
|
-
1. Check type
|
158
|
-
If it is
|
156
|
+
1. Check the type value from the metadata `#{prefix}fields[:#{field_name}][:type]`.
|
157
|
+
If it is absent, specify the type as shown in the example below:
|
159
158
|
|
160
|
-
#{prefix}fields[:#{field_name}][:type] = 'string'
|
159
|
+
#{prefix}fields[:#{field_name}][:type] = 'string' # or the specified type
|
161
160
|
|
162
|
-
2. If metadata `#{prefix}
|
163
|
-
|
161
|
+
2. If the metadata `#{prefix}fields[:#{field_name}]` is empty, the field may not exist.
|
162
|
+
Search for `index_field_names` and `#{field_name}` to determine if `#{field_name}` is inserted elsewhere.
|
163
|
+
|
164
|
+
3. If the metadata `#{prefix}fields` is empty, the table may not have been created yet,
|
165
|
+
or there may be an error in the decorator class declaration.
|
164
166
|
INSTRUCTION
|
165
|
-
)
|
166
167
|
end
|
167
168
|
end
|
168
169
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class IdRegexp < ResourcesRegexp
|
5
|
+
# This method works with {Map.resources_regexp} to complete the constraint restriction in `config/routes.rb`.
|
6
|
+
# This regular expression matches the ids which have all the possible resources names in front
|
7
|
+
#
|
8
|
+
# It looks like `((?<=products/)|(?<=orders/)|(?<=order/items/)|...|(?<!.))[^/]+`:
|
9
|
+
#
|
10
|
+
# - `(?<=products/)` is a positive lookbehind assertion,
|
11
|
+
# it means the ids must have `products/` in front of itself, but the match data won't include `products/`.
|
12
|
+
# it matches string e.g. `/admin/products/1`, and the match data is `1`.
|
13
|
+
# - `(?<!.)` is a negative lookbehind assertion,
|
14
|
+
# it means the ids must have nothing in front of itself.
|
15
|
+
# it matches string e.g. `1`, and the match data is `1`.
|
16
|
+
# this is required for URL helper when `:id` param is given,
|
17
|
+
# e.g. `resources_path(action: 'show', resources: 'products', id: 1)`
|
18
|
+
# - `[^/]+` is to match id. id can be anything as long as it doesn't contain `|` character.
|
19
|
+
def execute
|
20
|
+
Regexp.new(<<~REGEXP, Regexp::EXTENDED)
|
21
|
+
(
|
22
|
+
#{resources_sources.map { |resources| "(?<=#{resources}/)" }.join('|')} # all the possible resources names in front of the id
|
23
|
+
|(?<!.) # nothing is in front of the id, this is needed by URL helpers
|
24
|
+
)
|
25
|
+
[^/]+ # id
|
26
|
+
REGEXP
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
# This is designed to delegate all the methods to {#lazy_regexp}
|
5
|
+
# So that it doesn't need to load all the models for {Map.mode_map}
|
6
|
+
# when the engine is mounted in `config/routes.rb`
|
7
|
+
#
|
8
|
+
# @see Map.resources_regexp
|
9
|
+
# @see Map.id_regexp
|
10
|
+
class LazyRegexp < Regexp
|
11
|
+
delegate(*Regexp.instance_methods(false), to: :lazy_regexp)
|
12
|
+
|
13
|
+
def initialize(source, **options)
|
14
|
+
@lazy_source = source
|
15
|
+
super(source.to_s, **options)
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def lazy_regexp
|
21
|
+
Map.try(@lazy_source)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class ResourcesRegexp
|
5
|
+
# This method works with {Map.id_regexp} to complete the constraint restriction in `config/routes.rb`.
|
6
|
+
# This regular expression matches all the possible resources names that are loaded from the {.mode_map}
|
7
|
+
#
|
8
|
+
# It looks like `(products|orders|order/items|...)`
|
9
|
+
def execute
|
10
|
+
Regexp.new(<<~REGEXP, Regexp::EXTENDED)
|
11
|
+
(#{resources_sources.join('|')}) # all the possible resources names
|
12
|
+
REGEXP
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def resources_sources
|
18
|
+
# NOTE: `.reverse` is required so that for `order/items`,
|
19
|
+
# `%r{order/items|order}` matches `order/items`, not `order`
|
20
|
+
Map
|
21
|
+
.mode_map
|
22
|
+
.keys.flat_map { |klass| Inflector.to_resources_name(klass.to_s) }
|
23
|
+
.sort.reverse.uniq
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -31,7 +31,7 @@ module Wallaby
|
|
31
31
|
controller_class = find_controller_class_by(options)
|
32
32
|
controller_class.action(options[:action]).call(env)
|
33
33
|
rescue ::AbstractController::ActionNotFound, ModelNotFound => e
|
34
|
-
|
34
|
+
Wallaby::Logger.warn(e, sourcing: 1)
|
35
35
|
default_controller(options).action(:not_found).call(env)
|
36
36
|
rescue UnprocessableEntity => e
|
37
37
|
set_flash_error_for(e, env)
|
data/lib/wallaby/classifier.rb
CHANGED
@@ -7,10 +7,10 @@ module Wallaby
|
|
7
7
|
|
8
8
|
# Convert Class to String. If not Class, unchanged.
|
9
9
|
# @param klass [Object]
|
10
|
-
# @return [String] if klass is
|
11
|
-
# @return [
|
10
|
+
# @return [String] if klass is not nil
|
11
|
+
# @return [nil] if klass is nil or klass is an anonymous Class
|
12
12
|
def class_name_of(klass)
|
13
|
-
klass.try(:name)
|
13
|
+
klass.is_a?(Class) ? klass.try(:name) : klass.try(:to_s)
|
14
14
|
end
|
15
15
|
|
16
16
|
# Convert String to Class. If not String, unchanged.
|
@@ -18,13 +18,21 @@ module Wallaby
|
|
18
18
|
# @return [Class] if name is a Class
|
19
19
|
# @return [Object] if name is not a String
|
20
20
|
# @return [nil] if class cannot be found
|
21
|
-
def to_class(name)
|
22
|
-
return name unless name.is_a?
|
21
|
+
def to_class(name, raising: Wallaby.configuration.raise_on_name_error)
|
22
|
+
return name unless name.is_a?(String)
|
23
|
+
# blank string will lead to NameError `wrong constant name`
|
24
|
+
return if name.blank?
|
23
25
|
|
24
|
-
# NOTE: DO NOT try to use const_defined
|
25
|
-
#
|
26
|
+
# NOTE: DO NOT try to use `const_defined?` and `const_get` EVER.
|
27
|
+
# Rails does all the class loading magics using `constantize`
|
26
28
|
name.constantize
|
27
|
-
rescue NameError
|
29
|
+
rescue NameError => e
|
30
|
+
raise if raising
|
31
|
+
|
32
|
+
uninitialized = e.message.start_with?('uninitialized constant')
|
33
|
+
raise unless uninitialized
|
34
|
+
|
35
|
+
# block to handle this missing constant, e.g. use a default class or log useful instruction
|
28
36
|
yield(name) if block_given?
|
29
37
|
end
|
30
38
|
end
|
@@ -6,6 +6,9 @@ module Wallaby
|
|
6
6
|
class Configuration
|
7
7
|
include Classifier
|
8
8
|
|
9
|
+
# @!attribute [w] raise_on_name_error
|
10
|
+
attr_accessor :raise_on_name_error
|
11
|
+
|
9
12
|
# @!attribute [w] logger
|
10
13
|
attr_writer :logger
|
11
14
|
|
@@ -101,6 +104,7 @@ module Wallaby
|
|
101
104
|
Deprecator.alert 'config.models.presence', from: '0.3.0', alternative: <<~INSTRUCTION
|
102
105
|
Please use controller_class.models instead.
|
103
106
|
INSTRUCTION
|
107
|
+
@models ||= Models.new
|
104
108
|
end
|
105
109
|
|
106
110
|
# To globally configure the models that Wallaby should handle.
|
data/lib/wallaby/core/version.rb
CHANGED
data/lib/wallaby/core.rb
CHANGED
@@ -30,6 +30,9 @@ require 'wallaby/map'
|
|
30
30
|
|
31
31
|
require 'support/action_dispatch/routing/mapper'
|
32
32
|
|
33
|
+
require 'routes/wallaby/lazy_regexp'
|
34
|
+
require 'routes/wallaby/resources_regexp'
|
35
|
+
require 'routes/wallaby/id_regexp'
|
33
36
|
require 'routes/wallaby/resources_router'
|
34
37
|
require 'routes/wallaby/engines/base_route'
|
35
38
|
require 'routes/wallaby/engines/engine_route'
|
data/lib/wallaby/map.rb
CHANGED
@@ -90,6 +90,18 @@ module Wallaby
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
+
class << self
|
94
|
+
# @return [Regexp] regexp to match data for param `:resources`
|
95
|
+
def resources_regexp
|
96
|
+
@resources_regexp ||= ResourcesRegexp.new.execute
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [Regexp] regexp to match data for param `:id`
|
100
|
+
def id_regexp
|
101
|
+
@id_regexp ||= IdRegexp.new.execute
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
93
105
|
class << self
|
94
106
|
# Reset all the instance variables to nil
|
95
107
|
def clear
|
data/lib/wallaby/preloader.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wallaby-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Tianwen Chen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 6.0.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 8.0.0
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 6.0.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 8.0.0
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: railties
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -267,6 +273,9 @@ files:
|
|
267
273
|
- lib/routes/wallaby/engines/base_route.rb
|
268
274
|
- lib/routes/wallaby/engines/custom_app_route.rb
|
269
275
|
- lib/routes/wallaby/engines/engine_route.rb
|
276
|
+
- lib/routes/wallaby/id_regexp.rb
|
277
|
+
- lib/routes/wallaby/lazy_regexp.rb
|
278
|
+
- lib/routes/wallaby/resources_regexp.rb
|
270
279
|
- lib/routes/wallaby/resources_router.rb
|
271
280
|
- lib/servicers/wallaby/model_servicer.rb
|
272
281
|
- lib/services/wallaby/authorizer_finder.rb
|
@@ -317,13 +326,13 @@ files:
|
|
317
326
|
- lib/wallaby/logger.rb
|
318
327
|
- lib/wallaby/map.rb
|
319
328
|
- lib/wallaby/preloader.rb
|
320
|
-
homepage: https://github.com/wallaby-rails/wallaby-core
|
329
|
+
homepage: https://github.com/wallaby-rails/wallaby-rails/blob/main/wallaby-core
|
321
330
|
licenses:
|
322
331
|
- MIT
|
323
332
|
metadata:
|
324
|
-
homepage_uri: https://github.com/wallaby-rails/wallaby-core
|
325
|
-
source_code_uri: https://github.com/wallaby-rails/wallaby-core
|
326
|
-
changelog_uri: https://github.com/wallaby-rails/wallaby-
|
333
|
+
homepage_uri: https://github.com/wallaby-rails/wallaby-rails/blob/main/wallaby-core
|
334
|
+
source_code_uri: https://github.com/wallaby-rails/wallaby-rails/blob/main/wallaby-core
|
335
|
+
changelog_uri: https://github.com/wallaby-rails/wallaby-rails/blob/main/wallaby-core/CHANGELOG.md
|
327
336
|
rubygems_mfa_required: 'true'
|
328
337
|
post_install_message:
|
329
338
|
rdoc_options: []
|