wallaby-her 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3a2434677a3ae9ba231c0abf2baff2792ede04d441c26a63fc123a113e2baf13
4
+ data.tar.gz: 7c3d8bc9ef28b4e16fc7ae41426d5639f2076f37de309fd893fecf4c11c92984
5
+ SHA512:
6
+ metadata.gz: a282ef7b4e0c92ea744ce38cf2ba5791ee47f16335a5a45ca7d801a230e8cf1e5ec9f3fca400931d7c22d17c210978edc6b264063a1587a910c47b408b28e71a
7
+ data.tar.gz: 5b709969562097a838d9c414928b7ed04951164fa2021758c3308e30e61fb7445f6a903615dc3bcd0793ce74fa3a902ca8a74100940654c7baaf4654ef1776e9
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2010-2019 Google LLC. http://angular.io/license
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # Wallaby::Her
2
+
3
+ This gem contains the HER ORM adapter for Wallaby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'wallaby-her'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```shell
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```shell
22
+ $ gem install wallaby-her
23
+ ```
24
+
25
+ ## Contributing
26
+
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wallaby-rails/wallaby-her.
28
+
29
+ ## License
30
+
31
+ This project is [MIT Licensed](LICENSE)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ # Her mode
5
+ class Her < Mode
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ class Her
5
+ # Cancancan provider for Her
6
+ class CancancanProvider < CancancanAuthorizationProvider
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ class Her
5
+ # Default provider for Her
6
+ class DefaultProvider < DefaultAuthorizationProvider
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ class Her
5
+ # Modal decorator for Her
6
+ class ModelDecorator < ::Wallaby::ModelDecorator
7
+ # Generally, in Her, attribute methods are generated with this suffix
8
+ ATTRIBUTE_SUFFIX = '_will_change!'
9
+
10
+ # Origin metadata directly coming from Her.
11
+ #
12
+ # It needs to be frozen so that we can keep the metadata integrity
13
+ # @example sample fields:
14
+ # model_decorator.fields
15
+ # # =>
16
+ # {
17
+ # # general field
18
+ # id: { type: 'integer', label: 'Id' },
19
+ # # association field
20
+ # category: {
21
+ # 'type' => 'belongs_to',
22
+ # 'label' => 'Category',
23
+ # 'is_association' => true
24
+ # }
25
+ # }
26
+ # @return [ActiveSupport::HashWithIndifferentAccess] metadata
27
+ def fields
28
+ @fields ||= ::ActiveSupport::HashWithIndifferentAccess.new.tap do |hash|
29
+ hash.merge! general_fields
30
+ hash.merge! association_fields
31
+ end.freeze
32
+ end
33
+
34
+ # A copy of {#fields} for index page
35
+ # @return [ActiveSupport::HashWithIndifferentAccess] metadata
36
+ def index_fields
37
+ @index_fields ||= Utils.clone fields
38
+ end
39
+
40
+ # A copy of {#fields} for show page
41
+ # @return [ActiveSupport::HashWithIndifferentAccess] metadata
42
+ def show_fields
43
+ @show_fields ||= Utils.clone fields
44
+ end
45
+
46
+ # A copy of {#fields} for form (new/edit) page
47
+ # @return [ActiveSupport::HashWithIndifferentAccess] metadata
48
+ def form_fields
49
+ @form_fields ||= Utils.clone fields
50
+ end
51
+
52
+ # @return [Array<String>] a list of field names for index page
53
+ def index_field_names
54
+ @index_field_names ||=
55
+ index_fields.reject do |_field_name, metadata|
56
+ metadata[:is_association]
57
+ end.keys
58
+ end
59
+
60
+ # @return [Array<String>] a list of field names for form (new/edit) page
61
+ def form_field_names
62
+ @form_field_names ||=
63
+ Utils.clone(index_field_names)
64
+ .delete_if { |field_name| field_name == primary_key.to_s }
65
+ end
66
+
67
+ # @return [ActiveModel::Errors, Hash] errors for resource
68
+ # @see https://www.rubydoc.info/gems/her/Her/Model/Attributes/ClassMethods#store_response_errors-instance_method
69
+ # Her::Model::Attributes.store_response_errors
70
+ def form_active_errors(resource)
71
+ resource.errors.presence \
72
+ || resource.instance_variable_get(:@response_errors)
73
+ end
74
+
75
+ # @return [String] primary key for the resource
76
+ def primary_key
77
+ @primary_key ||= @model_class.primary_key
78
+ end
79
+
80
+ # To guess the title for resource.
81
+ #
82
+ # It will go through the fields and try to find out the one that looks
83
+ # like a name or text to represent this resource. Otherwise, it will fall
84
+ # back to primary key.
85
+ # @param resource [Object]
86
+ # @return [String] the title of given resource
87
+ def guess_title(resource)
88
+ ModuleUtils.try_to resource, possible_title_field
89
+ end
90
+
91
+ protected
92
+
93
+ # @return [Hash] a hash containing metadata for general fields
94
+ def general_fields
95
+ @general_fields ||=
96
+ her_attributes.each_with_object({}) do |attribute, fields|
97
+ fields[attribute.to_sym] = {
98
+ type: 'string',
99
+ label: @model_class.human_attribute_name(attribute)
100
+ }
101
+ end
102
+ end
103
+
104
+ # @return [Hash] a hash containing metadata for association fields
105
+ def association_fields
106
+ @association_fields ||=
107
+ @model_class.associations.each_with_object({}) do |(type, arr), hash|
108
+ arr.each do |assoc|
109
+ hash[assoc[:name]] = {
110
+ type: type.to_s.freeze,
111
+ label: @model_class.human_attribute_name(assoc[:name]),
112
+ is_association: true, sort_disabled: true
113
+ }
114
+ end
115
+ end
116
+ end
117
+
118
+ # @return [String] a field name that can be used as title (fall back to {#primary_key}).
119
+ def possible_title_field
120
+ @possible_title_field ||= begin
121
+ target_field = general_fields.keys.find do |field_name|
122
+ TITLE_NAMES.any? { |v| field_name.to_s.index v }
123
+ end
124
+ target_field || primary_key
125
+ end
126
+ end
127
+
128
+ # **Her::Model::Attributes.attributes** will produce seven methods for an
129
+ # attribute to track dirty data like ActiveModel
130
+ # @see https://www.rubydoc.info/gems/her/Her/Model/Attributes/ClassMethods#attributes-instance_method
131
+ # Her::Model::Attributes.attributes
132
+ # @return [Array<String>] a list of fields captured from instance methods
133
+ def her_attributes
134
+ instance_methods = @model_class.instance_methods
135
+ possible_attributes =
136
+ instance_methods.grep(/#{ATTRIBUTE_SUFFIX}$/).map do |method_id|
137
+ method_id.to_s[0...-ATTRIBUTE_SUFFIX.length]
138
+ end
139
+ attributes = possible_attributes.select do |attribute|
140
+ instance_methods.grep(/^#{attribute}\=?$/).length == 2 \
141
+ && attribute !~ /(index_|show_|form_)?fields/
142
+ end
143
+ attributes.unshift(primary_key)
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ class Her
5
+ # Model finder
6
+ class ModelFinder < ::Wallaby::ModelFinder
7
+ # Find out all the classes that include Her::Model
8
+ # @return [Array<Class>] a list of Her classes
9
+ def all
10
+ ObjectSpace
11
+ .each_object(Class)
12
+ .select do |klass|
13
+ klass < ::Her::Model && !ModuleUtils.anonymous_class?(klass)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ class Her
5
+ # Model pagination provider
6
+ class ModelPaginationProvider < ::Wallaby::ModelPaginationProvider
7
+ # By default, it doesn't support pagination as Her doesn't support
8
+ # @return [false]
9
+ def paginatable?
10
+ false
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ class Her
5
+ # Model service provider for HER ORM
6
+ class ModelServiceProvider < ::Wallaby::ModelServiceProvider
7
+ # Only the general fields will be permitted.
8
+ # It's less possible to guess what nested attributes should be permitted.
9
+ # @see Wallaby::ModelServiceProvider#permit
10
+ # @param params [ActionController::Parameters]
11
+ # @return [ActionController::Parameters] whitelisted parameters
12
+ def permit(params, action, authorizer)
13
+ authorized_fields = authorizer.permit_params action, @model_class
14
+ params.require(param_key).permit(authorized_fields || permitted_fields)
15
+ end
16
+
17
+ # No general practices of how ordering and searching can be done in Her.
18
+ # Therefore, it will just return all
19
+ #
20
+ # NOTE: pagination free here.
21
+ # Since somewhere might need the collection without any pagination
22
+ # @see Wallaby::ModelServiceProvider#collection
23
+ # @param _params [ActionController::Parameters]
24
+ # @param _authorizer [Ability] for now
25
+ # @return [ActiveRecord::Relation]
26
+ def collection(_params, _authorizer)
27
+ @model_class.all
28
+ end
29
+
30
+ # No general practices of how pagination can be done in Her.
31
+ # Therefore, it will just return all
32
+ #
33
+ # @see Wallaby::ModelServiceProvider#paginate
34
+ # @param query [ActiveRecord::Relation]
35
+ # @param _params [ActionController::Parameters]
36
+ # @return [ActiveRecord::Relation] paginated query
37
+ def paginate(query, _params)
38
+ query.all
39
+ end
40
+
41
+ # @see Wallaby::ModelServiceProvider#new
42
+ def new(_params, _authorizer)
43
+ @model_class.new
44
+ end
45
+
46
+ # @see Wallaby::ModelServiceProvider#find
47
+ # @param id [String]
48
+ def find(id, _params, _authorizer)
49
+ resource = @model_class.find id
50
+ raise ResourceNotFound, id unless resource
51
+
52
+ resource
53
+ end
54
+
55
+ # @see Wallaby::ModelServiceProvider#create
56
+ # @param resource [Object]
57
+ # @param params [ActionController::Parameters]
58
+ def create(resource, params, authorizer)
59
+ save __callee__, resource, params, authorizer
60
+ end
61
+
62
+ # @see Wallaby::ModelServiceProvider#update
63
+ # @param resource [Object]
64
+ # @param params [ActionController::Parameters]
65
+ def update(resource, params, authorizer)
66
+ save __callee__, resource, params, authorizer
67
+ end
68
+
69
+ # @see Wallaby::ModelServiceProvider#destroy
70
+ # @param resource [Object]
71
+ # @param _params [ActionController::Parameters]
72
+ def destroy(resource, _params, _authorizer)
73
+ resource.destroy
74
+ end
75
+
76
+ protected
77
+
78
+ # Save the record
79
+ # @param action [String] `create`, `update`
80
+ # @param resource [Object]
81
+ # @param params [ActionController::Parameters]
82
+ # @param authorizer [Object]
83
+ # @return resource itself
84
+ def save(action, resource, params, authorizer)
85
+ resource.assign_attributes params.to_h
86
+ ensure_attributes_for authorizer, action, resource
87
+ resource.save if resource.valid?
88
+ resource
89
+ rescue ActionController::UnfilteredParameters => e
90
+ resource.errors.add :base, e.message
91
+ resource
92
+ end
93
+
94
+ # To make sure that the record can be updated with the values that are
95
+ # allowed to.
96
+ # @param authorizer [Object]
97
+ # @param action [String]
98
+ # @param resource [Object]
99
+ def ensure_attributes_for(authorizer, action, resource)
100
+ return if authorizer.blank?
101
+
102
+ restricted_conditions = authorizer.attributes_for action, resource
103
+ resource.assign_attributes restricted_conditions
104
+ end
105
+
106
+ # @return [String] the params key
107
+ def param_key
108
+ @model_class.model_name.param_key
109
+ end
110
+
111
+ # The list of attributes to whitelist.
112
+ # For now, only general fields can be whitelisted.
113
+ # @return [Array]
114
+ def permitted_fields
115
+ @permitted_fields ||=
116
+ @model_decorator.fields.reject do |_field_name, metadata|
117
+ metadata[:is_association]
118
+ end.keys
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ class Her
5
+ # Pundit provider for Her
6
+ class PunditProvider < PunditAuthorizationProvider
7
+ # Find out the class and filter scope.
8
+ # @param _action [Symbol, String]
9
+ # @param scope [Object]
10
+ # @return [Object]
11
+ def accessible_for(_action, scope)
12
+ klass =
13
+ if scope.is_a? ::Her::Model::Relation
14
+ scope.instance_variable_get :@parent
15
+ else
16
+ scope
17
+ end
18
+ scope_policy = Pundit::PolicyFinder.new(klass).scope
19
+ scope_policy ? scope_policy.new(user, scope).resolve : scope
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wallaby/core'
4
+
5
+ require 'wallaby/her/version'
6
+
7
+ # All files here is for HER ORM
8
+ require 'her'
9
+ require 'adapters/wallaby/her'
10
+ require 'adapters/wallaby/her/model_finder'
11
+
12
+ # ModelDecorator: begin
13
+ require 'adapters/wallaby/her/model_decorator'
14
+ # ModelDecorator: end
15
+
16
+ # ModelPaginationProvider: begin
17
+ require 'adapters/wallaby/her/model_pagination_provider'
18
+ # ModelPaginationProvider: end
19
+
20
+ # ModelServiceProvider: begin
21
+ require 'adapters/wallaby/her/model_service_provider'
22
+ # ModelServiceProvider: end
23
+
24
+ # AuthorizationProvider: begin
25
+ require 'adapters/wallaby/her/default_provider'
26
+ require 'adapters/wallaby/her/cancancan_provider'
27
+ require 'adapters/wallaby/her/pundit_provider'
28
+ # AuthorizationProvider: end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wallaby
4
+ module HerGem
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wallaby-her
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tian Chen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: her
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: wallaby-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cancancan
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pundit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: wallaby-cop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Wallaby's HER ORM adapter
98
+ email:
99
+ - me@tian.im
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - LICENSE
105
+ - README.md
106
+ - lib/adapters/wallaby/her.rb
107
+ - lib/adapters/wallaby/her/cancancan_provider.rb
108
+ - lib/adapters/wallaby/her/default_provider.rb
109
+ - lib/adapters/wallaby/her/model_decorator.rb
110
+ - lib/adapters/wallaby/her/model_finder.rb
111
+ - lib/adapters/wallaby/her/model_pagination_provider.rb
112
+ - lib/adapters/wallaby/her/model_service_provider.rb
113
+ - lib/adapters/wallaby/her/pundit_provider.rb
114
+ - lib/wallaby/her.rb
115
+ - lib/wallaby/her/version.rb
116
+ homepage: https://github.com/wallaby-rails/wallaby-her
117
+ licenses:
118
+ - MIT
119
+ metadata:
120
+ homepage_uri: https://github.com/wallaby-rails/wallaby-her
121
+ source_code_uri: https://github.com/wallaby-rails/wallaby-her
122
+ changelog_uri: https://github.com/wallaby-rails/wallaby-her/blob/master/CHANGELOG.md
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.0.6
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Wallaby's HER ORM adapter
142
+ test_files: []