wallaby-core 0.1.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 +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,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Model finder interface
|
|
5
|
+
class ModelFinder
|
|
6
|
+
# Need to implement this method to get all the available model for a mode
|
|
7
|
+
# @return [Array<Class>] a list of model class
|
|
8
|
+
def all
|
|
9
|
+
raise NotImplemented
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Model pagination provider interface
|
|
5
|
+
class ModelPaginationProvider
|
|
6
|
+
# @param collection [#to_a]
|
|
7
|
+
# @param params [ActionController::Parameters]
|
|
8
|
+
# @param options [Hash] options
|
|
9
|
+
# @param model_decorator [Wallaby::ModelDecorator, nil]
|
|
10
|
+
def initialize(collection, params, options: {}, model_decorator: nil)
|
|
11
|
+
@collection = collection
|
|
12
|
+
@params = params
|
|
13
|
+
@options = options
|
|
14
|
+
@model_decorator = model_decorator
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# If a collection has pagination feature
|
|
18
|
+
# @return [Boolean]
|
|
19
|
+
def paginatable?
|
|
20
|
+
raise NotImplemented
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Check and see if it's the first page
|
|
24
|
+
# @return [Boolean]
|
|
25
|
+
def first_page?
|
|
26
|
+
page_number > first_page_number
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Check and see if it's the previous page
|
|
30
|
+
# @return [Boolean]
|
|
31
|
+
def prev_page?
|
|
32
|
+
page_number > first_page_number
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Check and see if it's the last page
|
|
36
|
+
# @return [Boolean]
|
|
37
|
+
def last_page?
|
|
38
|
+
page_number < last_page_number
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Check and see if it's the next page
|
|
42
|
+
# @return [Boolean]
|
|
43
|
+
def next_page?
|
|
44
|
+
page_number < last_page_number
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Find out the offset `from`
|
|
48
|
+
# @return [Integer]
|
|
49
|
+
def from
|
|
50
|
+
total.zero? ? total : (page_number - 1) * page_size + 1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Find out the offset `to`
|
|
54
|
+
# @return [Integer]
|
|
55
|
+
def to
|
|
56
|
+
[page_number * page_size, total].min
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Find out the total count of current query
|
|
60
|
+
# @return [Integer]
|
|
61
|
+
def total
|
|
62
|
+
raise NotImplemented
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Find out the current page size
|
|
66
|
+
# @return [Integer]
|
|
67
|
+
def page_size
|
|
68
|
+
raise NotImplemented
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Find out the current page number
|
|
72
|
+
# @return [Integer]
|
|
73
|
+
def page_number
|
|
74
|
+
raise NotImplemented
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Page number of first page
|
|
78
|
+
# @return [Integer]
|
|
79
|
+
def first_page_number
|
|
80
|
+
1
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Page number of last page
|
|
84
|
+
# @return [Integer]
|
|
85
|
+
def last_page_number
|
|
86
|
+
number_of_pages
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Page number of previous page
|
|
90
|
+
# @return [Integer]
|
|
91
|
+
def prev_page_number
|
|
92
|
+
[page_number - 1, first_page_number].max
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Page number of next page
|
|
96
|
+
# @return [Integer]
|
|
97
|
+
def next_page_number
|
|
98
|
+
[page_number + 1, last_page_number].min
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Total number of pages
|
|
102
|
+
# @return [Integer]
|
|
103
|
+
def number_of_pages
|
|
104
|
+
(total / page_size.to_f).ceil
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Model service provider interface
|
|
5
|
+
class ModelServiceProvider
|
|
6
|
+
# @param model_class [Class]
|
|
7
|
+
# @param model_decorator [Wallaby::ModelDecorator, nil] model decorator
|
|
8
|
+
def initialize(model_class, model_decorator)
|
|
9
|
+
raise ::ArgumentError, 'model class required' unless model_class
|
|
10
|
+
|
|
11
|
+
@model_class = model_class
|
|
12
|
+
@model_decorator = model_decorator
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# To whitelist params for a model class
|
|
16
|
+
# @param _params [ActionController::Parameters]
|
|
17
|
+
# @param _action [String, Symbol]
|
|
18
|
+
# @param _authorizer [Wallaby::ModelAuthorizer]
|
|
19
|
+
# @return [ActionController::Parameters] whitelisted params
|
|
20
|
+
def permit(_params, _action, _authorizer)
|
|
21
|
+
raise NotImplemented
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Fetch collection by params
|
|
25
|
+
# @param _params [ActionController::Parameters]
|
|
26
|
+
# @param _authorizer
|
|
27
|
+
# @return [#to_a]
|
|
28
|
+
def collection(_params, _authorizer)
|
|
29
|
+
raise NotImplemented
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Paginate the resources
|
|
33
|
+
# @param _query
|
|
34
|
+
# @param _params [ActionController::Parameters]
|
|
35
|
+
# @return [#to_a]
|
|
36
|
+
def paginate(_query, _params)
|
|
37
|
+
raise NotImplemented
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Initialize the model class using params
|
|
41
|
+
# @param _params [ActionController::Parameters]
|
|
42
|
+
# @param _authorizer
|
|
43
|
+
# @return a resource object
|
|
44
|
+
def new(_params, _authorizer)
|
|
45
|
+
raise NotImplemented
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Find a resource using id
|
|
49
|
+
# @param _id [Object]
|
|
50
|
+
# @param _params [ActionController::Parameters]
|
|
51
|
+
# @param _authorizer
|
|
52
|
+
# @return a resource object
|
|
53
|
+
def find(_id, _params, _authorizer)
|
|
54
|
+
raise NotImplemented
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Save the newly initialized resource
|
|
58
|
+
# @param _resource [Object]
|
|
59
|
+
# @param _params [ActionController::Parameters]
|
|
60
|
+
# @param _authorizer
|
|
61
|
+
# @return a resource object
|
|
62
|
+
def create(_resource, _params, _authorizer)
|
|
63
|
+
raise NotImplemented
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Update the persisted resource
|
|
67
|
+
# @param _resource [Object]
|
|
68
|
+
# @param _params [ActionController::Parameters]
|
|
69
|
+
# @param _authorizer
|
|
70
|
+
# @return a resource object
|
|
71
|
+
def update(_resource, _params, _authorizer)
|
|
72
|
+
raise NotImplemented
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Destroy the given resource
|
|
76
|
+
# @param _resource [Object]
|
|
77
|
+
# @param _params [ActionController::Parameters]
|
|
78
|
+
# @param _authorizer
|
|
79
|
+
# @return a resource object
|
|
80
|
+
def destroy(_resource, _params, _authorizer)
|
|
81
|
+
raise NotImplemented
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Model paginator to provide support for pagination on index page
|
|
5
|
+
class ModelPaginator
|
|
6
|
+
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 **ProductPaginator**.
|
|
14
|
+
#
|
|
15
|
+
# If Wallaby can't recognise the model class for Paginator, it's required to be configured as below example:
|
|
16
|
+
# @example To configure model class
|
|
17
|
+
# class Admin::ProductPaginator < Admin::ApplicationPaginator
|
|
18
|
+
# self.model_class = Product
|
|
19
|
+
# end
|
|
20
|
+
# @example To configure model class for version below 5.2.0
|
|
21
|
+
# class Admin::ProductPaginator < Admin::ApplicationPaginator
|
|
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_paginator}
|
|
29
|
+
# @return [nil] if current class is {Wallaby::ModelPaginator}
|
|
30
|
+
# @return [nil] if assoicated model class is not found
|
|
31
|
+
def model_class
|
|
32
|
+
return unless self < ModelPaginator
|
|
33
|
+
return if base_class? || self == Wallaby.configuration.mapping.model_paginator
|
|
34
|
+
|
|
35
|
+
@model_class ||= Map.model_class_map(name.gsub(/(^#{namespace}::)|(Paginator$)/, EMPTY_STRING))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @!attribute provider_class
|
|
39
|
+
# @return [Class] pagination provider class
|
|
40
|
+
# @since 5.2.0
|
|
41
|
+
attr_accessor :provider_class
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @!attribute [r] model_class
|
|
45
|
+
# @return [Class]
|
|
46
|
+
attr_reader :model_class
|
|
47
|
+
|
|
48
|
+
# @!attribute [r] provider
|
|
49
|
+
# @return [Wallaby::ModelServiceProvider]
|
|
50
|
+
# @since 5.2.0
|
|
51
|
+
attr_reader :provider
|
|
52
|
+
|
|
53
|
+
# During initialization, Wallaby will assign a pagination provider for this paginator
|
|
54
|
+
# to carry out the actual execution.
|
|
55
|
+
#
|
|
56
|
+
# Therefore, all its actions can be completely replaced by user's own implemnetation.
|
|
57
|
+
# @param model_class [Class]
|
|
58
|
+
# @param collection [#to_a] a collection of the resources
|
|
59
|
+
# @param params [ActionController::Parameters]
|
|
60
|
+
def initialize(model_class, collection, params)
|
|
61
|
+
@model_class = self.class.model_class || model_class
|
|
62
|
+
raise ArgumentError, I18n.t('errors.required', subject: 'model_class') unless @model_class
|
|
63
|
+
|
|
64
|
+
@collection = collection
|
|
65
|
+
@params = params
|
|
66
|
+
@provider = Map.pagination_provider_map(@model_class).new(@collection, @params)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
delegate(*ModelPaginationProvider.instance_methods(false), to: :provider)
|
|
70
|
+
# @!method paginatable?
|
|
71
|
+
# (see Wallaby::ModelPaginationProvider#paginatable?)
|
|
72
|
+
|
|
73
|
+
# @!method first_page?
|
|
74
|
+
# (see Wallaby::ModelPaginationProvider#first_page?)
|
|
75
|
+
|
|
76
|
+
# @!method prev_page?
|
|
77
|
+
# (see Wallaby::ModelPaginationProvider#prev_page?)
|
|
78
|
+
|
|
79
|
+
# @!method last_page?
|
|
80
|
+
# (see Wallaby::ModelPaginationProvider#last_page?)
|
|
81
|
+
|
|
82
|
+
# @!method next_page?
|
|
83
|
+
# (see Wallaby::ModelPaginationProvider#next_page?)
|
|
84
|
+
|
|
85
|
+
# @!method from
|
|
86
|
+
# (see Wallaby::ModelPaginationProvider#from)
|
|
87
|
+
|
|
88
|
+
# @!method to
|
|
89
|
+
# (see Wallaby::ModelPaginationProvider#to)
|
|
90
|
+
|
|
91
|
+
# @!method total
|
|
92
|
+
# (see Wallaby::ModelPaginationProvider#total)
|
|
93
|
+
|
|
94
|
+
# @!method page_size
|
|
95
|
+
# (see Wallaby::ModelPaginationProvider#page_size)
|
|
96
|
+
|
|
97
|
+
# @!method page_number
|
|
98
|
+
# (see Wallaby::ModelPaginationProvider#page_number)
|
|
99
|
+
|
|
100
|
+
# @!method first_page_number
|
|
101
|
+
# (see Wallaby::ModelPaginationProvider#first_page_number)
|
|
102
|
+
|
|
103
|
+
# @!method last_page_number
|
|
104
|
+
# (see Wallaby::ModelPaginationProvider#last_page_number)
|
|
105
|
+
|
|
106
|
+
# @!method prev_page_number
|
|
107
|
+
# (see Wallaby::ModelPaginationProvider#prev_page_number)
|
|
108
|
+
|
|
109
|
+
# @!method next_page_number
|
|
110
|
+
# (see Wallaby::ModelPaginationProvider#next_page_number)
|
|
111
|
+
|
|
112
|
+
# @!method number_of_pages
|
|
113
|
+
# (see Wallaby::ModelPaginationProvider#number_of_pages)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Resource paginator
|
|
5
|
+
class ResourcePaginator < ModelPaginator
|
|
6
|
+
base_class!
|
|
7
|
+
|
|
8
|
+
def self.inherited(_sub_class)
|
|
9
|
+
Utils.deprecate 'deprecation.resource_paginator_inheirtance', caller: caller
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# a parser to handle colon query
|
|
5
|
+
class Parser < Parslet::Parser
|
|
6
|
+
root(:statement)
|
|
7
|
+
rule(:statement) { expression >> (space >> expression).repeat }
|
|
8
|
+
rule(:expression) { colon_query | general_keyword }
|
|
9
|
+
rule(:colon_query) do
|
|
10
|
+
name.as(:left) >> operator.as(:op) >> keywords.as(:right)
|
|
11
|
+
end
|
|
12
|
+
rule(:name) { (space.absent? >> colon.absent? >> any).repeat(1) }
|
|
13
|
+
rule(:operator) { colon >> match('[^\s\'\"\:\,0-9a-zA-Z]').repeat(0, 3) }
|
|
14
|
+
rule(:keywords) { general_keyword >> (comma >> general_keyword).repeat }
|
|
15
|
+
rule(:general_keyword) { quoted_keyword | keyword }
|
|
16
|
+
|
|
17
|
+
# basic elements
|
|
18
|
+
rule(:quoted_keyword) do
|
|
19
|
+
open_quote >>
|
|
20
|
+
(close_quote.absent? >> any).repeat.as(:keyword) >>
|
|
21
|
+
close_quote
|
|
22
|
+
end
|
|
23
|
+
rule(:keyword) { ((space | comma).absent? >> any).repeat.as(:keyword) }
|
|
24
|
+
|
|
25
|
+
# atomic entities
|
|
26
|
+
rule(:comma) { str(',') }
|
|
27
|
+
rule(:space) { match('\s').repeat(1) }
|
|
28
|
+
rule(:colon) { str(':') }
|
|
29
|
+
|
|
30
|
+
# open-close elements
|
|
31
|
+
rule(:open_quote) { match('[\'\"]').capture(:quote) }
|
|
32
|
+
rule(:close_quote) { dynamic { |_src, ctx| str(ctx.captures[:quote]) } }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# In order to improve the rendering performance, cell is designed as simple partial component.
|
|
5
|
+
# @since 5.2.0
|
|
6
|
+
class Cell
|
|
7
|
+
# @!attribute [r] context
|
|
8
|
+
# @return [Object] view context
|
|
9
|
+
attr_reader :context
|
|
10
|
+
|
|
11
|
+
# @!attribute [r] local_assigns
|
|
12
|
+
# @return [Hash] a list of local_assigns containing {#object}, {#field_name}, {#value}, {#metadata} and {#form}
|
|
13
|
+
attr_reader :local_assigns
|
|
14
|
+
|
|
15
|
+
# @!attribute [r] buffer
|
|
16
|
+
# @return [String] output string buffer
|
|
17
|
+
attr_reader :buffer
|
|
18
|
+
|
|
19
|
+
delegate(*ERB::Util.singleton_methods, to: ERB::Util)
|
|
20
|
+
|
|
21
|
+
# @param context [ActionView::Context] view context
|
|
22
|
+
# @param local_assigns [Hash] local variables
|
|
23
|
+
def initialize(context, local_assigns)
|
|
24
|
+
@context = context
|
|
25
|
+
@local_assigns = local_assigns
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @!attribute [r] object
|
|
29
|
+
# @return [Object] object
|
|
30
|
+
def object
|
|
31
|
+
local_assigns[:object]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @!attribute [w] object
|
|
35
|
+
def object=(object)
|
|
36
|
+
local_assigns[:object] = object
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @!attribute [r] field_name
|
|
40
|
+
# @return [String] field name
|
|
41
|
+
def field_name
|
|
42
|
+
local_assigns[:field_name]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @!attribute [w] field_name
|
|
46
|
+
def field_name=(field_name)
|
|
47
|
+
local_assigns[:field_name] = field_name
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @!attribute [r] value
|
|
51
|
+
# @return [String] value
|
|
52
|
+
def value
|
|
53
|
+
local_assigns[:value]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @!attribute [w] value
|
|
57
|
+
def value=(value)
|
|
58
|
+
local_assigns[:value] = value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @!attribute [r] metadata
|
|
62
|
+
# @return [String] metadata
|
|
63
|
+
def metadata
|
|
64
|
+
local_assigns[:metadata]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @!attribute [w] metadata
|
|
68
|
+
def metadata=(metadata)
|
|
69
|
+
local_assigns[:metadata] = metadata
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @!attribute [r] form
|
|
73
|
+
# @return [ActionView::Helpers::FormBuilder] form object
|
|
74
|
+
def form
|
|
75
|
+
local_assigns[:form]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @!attribute [w] form
|
|
79
|
+
def form=(form)
|
|
80
|
+
local_assigns[:form] = form
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @note this is a template method that can be overridden by subclasses
|
|
84
|
+
# Produce output for this cell component.
|
|
85
|
+
#
|
|
86
|
+
# Please note that the output doesn't include the buffer produced by {#concat}.
|
|
87
|
+
# Therefore, use {#render_complete} method instead when the cell is rendered.
|
|
88
|
+
def render; end
|
|
89
|
+
|
|
90
|
+
# This method produces the complete rendered string including the buffer produced by {#concat}.
|
|
91
|
+
# @return [String] output of the cell
|
|
92
|
+
def render_complete(&block)
|
|
93
|
+
@buffer = EMPTY_STRING.dup # reset buffer before rendering
|
|
94
|
+
last_part = render(&block)
|
|
95
|
+
@buffer << last_part.to_s
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Append string to output buffer
|
|
99
|
+
# @param string [String] string to concat
|
|
100
|
+
def concat(string)
|
|
101
|
+
(@buffer ||= EMPTY_STRING.dup) << string
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @overload at(name)
|
|
105
|
+
# Get view instance variable value
|
|
106
|
+
# @example To get view instance variable value
|
|
107
|
+
# at('name') # => get value of `@name` from the view
|
|
108
|
+
# @param name [String, Symbol] view instance variable name without `@`
|
|
109
|
+
# @overload at(name, value)
|
|
110
|
+
# Set view instance variable value
|
|
111
|
+
# @example To set view instance variable value
|
|
112
|
+
# at('name', value) # => set value of `@name` in the view
|
|
113
|
+
# @param name [String, Symbol] view instance variable name without `@`
|
|
114
|
+
# @param value [object] value
|
|
115
|
+
# @return [object] view instance variable value
|
|
116
|
+
def at(*args)
|
|
117
|
+
raise ArgumentError unless args.length.in? [1, 2]
|
|
118
|
+
return context.instance_variable_get :"@#{args.first}" if args.length == 1
|
|
119
|
+
|
|
120
|
+
context.instance_variable_set :"@#{args.first}", args.last
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
|
|
125
|
+
# Delegate missing method to {#context}
|
|
126
|
+
def method_missing(method_id, *args, &block)
|
|
127
|
+
return super unless context.respond_to? method_id
|
|
128
|
+
|
|
129
|
+
context.public_send method_id, *args, &block
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Delegate missing method check to {#context}
|
|
133
|
+
def respond_to_missing?(method_id, _include_private)
|
|
134
|
+
context.respond_to?(method_id) || super
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|