granite-form 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb26aa530c266a54d01fe3723d4ee44a95bedbefb140a5358403ebcdf78ced5c
4
- data.tar.gz: 1c63d7e31c87a934a6c858c24c396f0547e16268997dcd2c2e8dbeac16ba98d5
3
+ metadata.gz: df27378689a1bdcdc95593c32c65046ecaab452cc3303839979ace6f1a12ef0f
4
+ data.tar.gz: 41b0ee8c8b22f1cf992e7b46c91528b4596ad6b362930c5299b6fde58a9bd2b8
5
5
  SHA512:
6
- metadata.gz: 2b28feea4881f8c4f6635f1e626345b4ea534306b8596deb8a61f2a38ce428950eb957bd9b1c936699fbe049a22e1c41d36dce4ebd695c769b3fee39c3ecf716
7
- data.tar.gz: e0fdbd61872e007edaf0cf4ffed388b382f14e53e2637a04979eae1f4e2f1b67aa0bad71569b9ab4b2ce8cd2363820e380661f402edec70584c480962aa7c0e1
6
+ metadata.gz: aef5479a5c58afc85c8e68635fbd8382039c69b8235beaeda74d5caf320540c2fd8aac330f70f4c031abfd37d6a214c3acab0086c9c0a1d3843aedd7aab5a1db
7
+ data.tar.gz: 5fcc7f498c8685167096ec9d835c6cc80efec7915b17c32aa27f8e912776d2ef25e215ed24c076e7c8e4cb32790eba060d8a7aac827ff1c2cd8d93819b7ae7e2
@@ -0,0 +1,2 @@
1
+ .github/workflows/ci.yml @toptal/coresmiths-team
2
+ .github/workflows/main.yml @toptal/coresmiths-team
data/CHANGELOG.md CHANGED
@@ -1,73 +1,9 @@
1
1
  # master
2
2
 
3
- # Version 1.2.0
3
+ ## v0.1.1
4
4
 
5
- * Rails 6.1 and 7 support (#80). Thanks to @ojab and @rewritten
5
+ - Fixed represented error message copying when represented model uses symbols for `message`.
6
6
 
7
- # Version 1.1.7
7
+ ## v0.1.0
8
8
 
9
- * Add typecasting from `ActionController::Parameters` to `Hash` (#73)
10
-
11
- # Version 1.1.6
12
-
13
- * Fix Ruby 2.6 deprecations (#72)
14
-
15
- # Version 1.1.5
16
-
17
- * Rails 6 support (#70, #71)
18
-
19
- # Version 1.1.4
20
-
21
- ## Changes
22
-
23
- * `came_from_default?` attribute method (#66)
24
-
25
- # Version 1.1.3
26
-
27
- ## Changes
28
-
29
- * `came_from_user?` attribute method (#65)
30
-
31
- # Version 1.1.2
32
-
33
- ## Changes
34
-
35
- * `ActiveData.base_concern` config option in addition to `ActiveData.base_class` (#64)
36
-
37
- # Version 1.1.1
38
-
39
- ## Changes
40
-
41
- * `ActiveData.base_class` config option (#63)
42
-
43
- * ActiveModel 5.2 compatibility (#62)
44
-
45
- # Version 1.1.0
46
-
47
- ## Incompatible changes
48
-
49
- * Represented attributes are not provided by default, to add them, `include ActiveData::Model::Representation` (#46)
50
-
51
- * `include ActiveData::Model::Associations::Validations` is not included by default anymore, to get `validate_ancestry!`, `valid_ancestry?` and `invalid_ancestry?` methods back you need to include this module manually
52
-
53
- ## Changes
54
-
55
- * Introduce persistence adapters for associations (#24, #51)
56
-
57
- * `ActionController::Parameters` support (#43)
58
-
59
- * Nested attributes simple method overriding (#41)
60
-
61
- * Persistence for `references` associations (#28, #32)
62
-
63
- * Support `update_only` option on collection nested attributes (#30)
64
-
65
- * `embedder` accessor for embedded associations
66
-
67
- * Dynamic scopes for `references` associations (#27)
68
-
69
- ## Bugfixes
70
-
71
- * Fixed multiple validations on represented attributes and associations (#44)
72
-
73
- * Proper boolean attributes defaults (#31, #33)
9
+ - Forked from ActiveData, see https://github.com/pyromaniac/active_data/blob/v1.2.0/CHANGELOG.md for changes before this
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # Granite::Form
5
5
 
6
- Granite::Form is a ActiveModel-based front-end for your data. You might need to use it in the following cases:
6
+ `Granite::Form` is an `ActiveModel`-based front-end for your data. It is useful in the following cases:
7
7
 
8
8
  * When you need a form objects pattern.
9
9
 
@@ -43,7 +43,7 @@ class ProfileController < ApplicationController
43
43
  end
44
44
  ```
45
45
 
46
- * When you need to work with data-storage in ActiveRecord style with
46
+ * When you need to work with data storage à la `ActiveRecord`.
47
47
 
48
48
  ```ruby
49
49
  class Flight
@@ -75,7 +75,7 @@ class Flight
75
75
  end
76
76
  ```
77
77
 
78
- * When you need to implement embedded objects for ActiveRecord models
78
+ * When you need to embed objects in `ActiveRecord` models.
79
79
 
80
80
  ```ruby
81
81
  class Answer
@@ -94,25 +94,25 @@ class Quiz < ActiveRecord::Base
94
94
  validates :answers, associated: true
95
95
  end
96
96
 
97
- q = Quiz.new
98
- q.answers.build(question_id: 42, content: 'blabla')
99
- q.save
97
+ quiz = Quiz.new
98
+ quiz.answers.build(question_id: 42, content: 'blabla')
99
+ quiz.save
100
100
  ```
101
101
 
102
102
  ## Why?
103
103
 
104
- Granite::Form is an ActiveModel-based library that provides the following abilities:
104
+ `Granite::Form` is an `ActiveModel-based library that provides the following functionalities:
105
105
 
106
106
  * Standard form objects building toolkit: attributes with typecasting, validations, etc.
107
107
  * High-level universal ORM/ODM library using any data source (DB, http, redis, text files).
108
- * Embedding objects into your ActiveRecord entities. Quite useful with PG JSON capabilities.
108
+ * Embedding objects into ActiveRecord entities. Quite useful with PG JSON capabilities.
109
109
 
110
110
  Key features:
111
111
 
112
- * Complete objects lifecycle support: saving, updating, destroying.
112
+ * Complete object lifecycle support: saving, updating, destroying.
113
113
  * Embedded and referenced associations.
114
- * Backend-agnostic named scopes functionality.
115
- * Callbacks, validations and dirty attributes inside.
114
+ * Backend-agnostic named scopes.
115
+ * Callbacks, validations and dirty attributes.
116
116
 
117
117
  ## Installation
118
118
 
@@ -130,11 +130,11 @@ Or install it yourself as:
130
130
 
131
131
  ## Usage
132
132
 
133
- Granite::Form has modular architecture, so it is required to include modules to obtain additional features. By default Granite::Form supports attributes definition and validations.
133
+ `Granite::Form` has modular architecture, so it is required to include modules to obtain additional features. By default `Granite::Form` supports attributes definition and validations.
134
134
 
135
135
  ### Attributes
136
136
 
137
- Granite::Form provides several types of attributes and typecasts each attribute to its defined type upon initialization.
137
+ `Granite::Form` provides several types of attributes and typecasts each attribute to its defined type upon initialization.
138
138
 
139
139
  ```ruby
140
140
  class Book
@@ -151,16 +151,16 @@ end
151
151
  attribute :full_name, String, default: 'John Talbot'
152
152
  ```
153
153
 
154
- By default, if type for attribute is not set, it is defined with `Object` type, so it would be a great idea to specify type for every attribute explicitly.
154
+ If type for an attribute is not set, it defaults to `Object`. It is therefore recommended to specify the type for every attribute explicitly.
155
155
 
156
- Type is necessary for attribute typecasting. Here is the list of pre-defined basic typecasters:
156
+ The type is necessary for attribute typecasting. Here is the list of pre-defined basic typecasters:
157
157
 
158
158
  ```irb
159
159
  [1] pry(main)> Granite::Form._typecasters.keys
160
160
  => ["Object", "String", "Array", "Hash", "Date", "DateTime", "Time", "ActiveSupport::TimeZone", "BigDecimal", "Float", "Integer", "Boolean", "Granite::Form::UUID"]
161
161
  ```
162
162
 
163
- In addition, you can provide any class type when defining the attribute, but in that case you will be able to only assign instances of that specific class or value nil:
163
+ In addition, you can provide any class type when defining an attribute, but in that case you will be able to only assign instances of that specific class or `nil`:
164
164
 
165
165
  ```ruby
166
166
  attribute :template, MyCustomTemplateType
@@ -168,7 +168,7 @@ attribute :template, MyCustomTemplateType
168
168
 
169
169
  ##### Defaults
170
170
 
171
- It is possible to provide default values for attributes and they will act in the same way as AR or Mongoid default values:
171
+ It is possible to provide default values for attributes and they will act in the same way as `ActiveRecord` or `Mongoid` default values:
172
172
 
173
173
  ```ruby
174
174
  attribute :check, Boolean, default: false # Simply false by default
@@ -179,7 +179,7 @@ attribute :today_wday, Integer, default: ->(instance) { instance.today.wday } #
179
179
 
180
180
  ##### Enums
181
181
 
182
- Enums restrict the scope of possible values for attribute. If assigned value is not included in provided list - then it turns to nil:
182
+ Enums restrict the scope of possible values for an attribute. If the assigned value is not included in the provided list, the attribute value is set to `nil`:
183
183
 
184
184
  ```ruby
185
185
  attribute :direction, String, enum: %w[north south east west]
@@ -187,7 +187,7 @@ attribute :direction, String, enum: %w[north south east west]
187
187
 
188
188
  ##### Normalizers
189
189
 
190
- Normalizers are applied last, modifying typecast value. It is possible to provide a list of normalizers, they will be applied in the order. It is possible to pre-define normalizers to DRY code:
190
+ Normalizers are applied last, modifying a typecast value. It is possible to provide a list of normalizers. They will be applied in the provided order. It is possible to pre-define normalizers to DRY code:
191
191
 
192
192
  ```ruby
193
193
  Granite::Form.normalizer(:trim) do |value, options, _attribute|
@@ -201,13 +201,13 @@ attribute :title, String, normalizers: [->(value) { value.strip }, trim: {length
201
201
 
202
202
  ```ruby
203
203
  attribute :name, String, readonly: true # Readonly forever
204
- attribute :name, String, readonly: ->{ true } # Conditionally readonly
204
+ attribute :name, String, readonly: -> { true } # Conditionally readonly
205
205
  attribute :name, String, readonly: ->(instance) { instance.subject.present? } # Explicit instance
206
206
  ```
207
207
 
208
208
  #### Collection
209
209
 
210
- Collection is simply an array of equally-typed values:
210
+ A collection is simply an array of equally-typed values:
211
211
 
212
212
  ```ruby
213
213
  class Panda
@@ -217,7 +217,7 @@ class Panda
217
217
  end
218
218
  ```
219
219
 
220
- Collection typecasts each value to specified type and also no matter what are you going to pass - it will be an array.
220
+ A collection typecasts each value to the specified type. Also, it normalizes any given value to an array.
221
221
 
222
222
  ```irb
223
223
  [1] pry(main)> Panda.new
@@ -228,11 +228,11 @@ Collection typecasts each value to specified type and also no matter what are yo
228
228
  => #<Panda ids: [42, 33]>
229
229
  ```
230
230
 
231
- Default and enum modifiers are applied to every value, normalizer will be applied to the whole array.
231
+ Default and enum modifiers are applied on each value, normalizers are applied on the array.
232
232
 
233
233
  #### Dictionary
234
234
 
235
- Dictionary field is a hash of specified type values with string keys:
235
+ A dictionary field is a hash of specified type values with string keys:
236
236
 
237
237
  ```ruby
238
238
  class Foo
@@ -249,11 +249,11 @@ end
249
249
  => #<Foo ordering: {"name"=>"desc"}>
250
250
  ```
251
251
 
252
- Keys list might be restricted with `:keys` option, defaults and enums are applied to every value, normalizers are applied to the whole hash.
252
+ The keys list might be restricted with the `:keys` option. Default and enum modifiers are applied on each value, normalizers are applied on the hash.
253
253
 
254
254
  #### Localized
255
255
 
256
- Localized is similar to how Globalize 3 attributes work.
256
+ `localized` is similar to how `Globalize 3` attributes work.
257
257
 
258
258
  ```ruby
259
259
  localized :title, String
@@ -261,11 +261,11 @@ localized :title, String
261
261
 
262
262
  #### Represents
263
263
 
264
- Represents provides an easy way to expose model attributes through an interface.
265
- It will automatically set passed value to the represented object **before validation**.
266
- You can use any ActiveRecord, ActiveModel or Granite::Form object as a target of representation.
267
- A type of an attribute will be taken from it.
268
- If there is no type, it will be `Object` by default. You can set the type explicitly by passing the `type: TypeClass` option.
264
+ `represents` provides an easy way to expose model attributes through an interface.
265
+ It will automatically set the passed value to the represented object **before validation**.
266
+ You can use any `ActiveRecord`, `ActiveModel` or `Granite::Form` object as a target of representation.
267
+ The type of an attribute will be taken from it.
268
+ If no type is defined, it will be `Object` by default. You can set the type explicitly by passing the `type: TypeClass` option.
269
269
  Represents will also add automatic validation of the target object.
270
270
 
271
271
  ```ruby
@@ -295,7 +295,7 @@ person.name
295
295
 
296
296
  ### Associations
297
297
 
298
- Granite::Form provides a set of associations. There are two types of them: referenced and embedded. The closest example of referenced association is AR `belongs_to` and as for embedded ones - Mongoid's embedded. Also these associations support `accepts_nested_attributes` call.
298
+ `Granite::Form` provides a set of associations. There are two types: referenced and embedded. The closest example of referenced association is `AcitveRecord`'s `belongs_to`. For embedded ones - Mongoid's embedded. Also these associations support `accepts_nested_attributes` calls.
299
299
 
300
300
  #### EmbedsOne
301
301
 
@@ -312,11 +312,11 @@ embeds_one :profile do
312
312
  end
313
313
  ```
314
314
 
315
- Possible options:
315
+ Оptions:
316
316
 
317
317
  * `:class_name` - association class name
318
- * `:validate` - true or false
319
- * `:default` - default value for association: attributes hash or instance of defined class
318
+ * `:validate` - `true` or `false`
319
+ * `:default` - default value for the association: an attributes hash or an instance of the defined class
320
320
 
321
321
  #### EmbedsMany
322
322
 
@@ -324,7 +324,7 @@ Possible options:
324
324
  embeds_many :tags
325
325
  ```
326
326
 
327
- Defines collection of embedded objects. Might be defined inline:
327
+ Defines a collection of embedded objects. Might be defined inline:
328
328
 
329
329
  ```ruby
330
330
  embeds_many :tags do
@@ -332,9 +332,11 @@ embeds_many :tags do
332
332
  end
333
333
  ```
334
334
 
335
+ Оptions:
336
+
335
337
  * `:class_name` - association class name
336
- * `:validate` - true or false
337
- * `:default` - default value for association: attributes hash collection or instances of defined class
338
+ * `:validate` - `true` or `false`
339
+ * `:default` - default value for the association: an attributes hash or an instance of the defined class
338
340
 
339
341
  #### ReferencesOne
340
342
 
@@ -342,22 +344,22 @@ end
342
344
  references_one :user
343
345
  ```
344
346
 
345
- This will provide several methods to the object: `#user`, `#user=`, `#user_id` and `#user_id=`, just as would occur with an ActiveRecord association.
347
+ Provides several methods to the object: `#user`, `#user=`, `#user_id` and `#user_id=`, similarly to an ActiveRecord association.
346
348
 
347
- Possible options:
349
+ Оptions:
348
350
 
349
351
  * `:class_name` - association class name
350
- * `:primary_key` - associated object primary key (`:id` by default):
352
+ * `:primary_key` - the associated object's primary key name (`:id` by default):
351
353
 
352
354
  ```ruby
353
355
  references_one :user, primary_key: :name
354
356
  ```
355
357
 
356
- This will create the following methods: `#user`, `#user=`, `#user_name` and `#user_name=`
358
+ Creates the following methods: `#user`, `#user=`, `#user_name` and `#user_name=`.
357
359
 
358
360
  * `:reference_key` - redefines `#user_id` and `#user_id=` method names completely.
359
- * `:validate` - true or false
360
- * `:default` - default value for association: reference or object itself
361
+ * `:validate` - `true` or `false`
362
+ * `:default` - default value for the association: reference or the object itself
361
363
 
362
364
  #### ReferencesMany
363
365
 
@@ -365,18 +367,18 @@ Possible options:
365
367
  references_many :users
366
368
  ```
367
369
 
368
- This will provide several methods to the object: `#users`, `#users=`, `#user_ids` and `#user_ids=` just as an ActiveRecord relation does.
370
+ Provides several methods to the object: `#users`, `#users=`, `#user_ids` and `#user_ids=`, similarly to an ActiveRecord association.
369
371
 
370
- Possible options:
372
+ Options:
371
373
 
372
374
  * `:class_name` - association class name
373
- * `:primary_key` - associated object primary key (`:id` by default):
375
+ * `:primary_key` - the associated object's primary key name (`:id` by default):
374
376
 
375
377
  ```ruby
376
378
  references_many :users, primary_key: :name
377
379
  ```
378
380
 
379
- This will create the following methods: `#users`, `#users=`, `#user_names` and `#user_names=`
381
+ Creates the following methods: `#users`, `#users=`, `#user_names` and `#user_names=`.
380
382
 
381
383
  * `:reference_key` - redefines `#user_ids` and `#user_ids=` method names completely.
382
384
  * `:validate` - true or false
@@ -396,15 +398,15 @@ class Mongoid::Document
396
398
  end
397
399
  end
398
400
  ```
399
- Where
401
+ where
400
402
  `ClassName` - name of model class or one of ancestors
401
403
  `data_source` - name of data source class
402
404
  `primary_key` - key to search data
403
405
  `scope_proc` - additional proc for filtering
404
406
 
405
- All required interface for adapters described in `Granite::Form::Model::Associations::PersistenceAdapters::Base`.
407
+ All requirements for the adapter interfaces are described in `Granite::Form::Model::Associations::PersistenceAdapters::Base`.
406
408
 
407
- Adapter for ActiveRecord is `Granite::Form::Model::Associations::PersistenceAdapters::ActiveRecord`. So, all AR models will use `PersistenceAdapters::ActiveRecord` by default.
409
+ The adapter for `ActiveRecord` is `Granite::Form::Model::Associations::PersistenceAdapters::ActiveRecord`. All `ActiveRecord` models use `PersistenceAdapters::ActiveRecord` by default.
408
410
 
409
411
  ### Primary
410
412
 
@@ -79,7 +79,7 @@ module Granite
79
79
  errors.where(from).each do |error|
80
80
  options = error.options
81
81
  # If we generate message for built-in validation, we don't want to later escape it in our monkey-patch
82
- options = options.merge(message: error.message.html_safe) unless options.key?(:message)
82
+ options = options.merge(message: error.message.html_safe)
83
83
 
84
84
  errors.add(to, error.type, **options)
85
85
  end
@@ -1,5 +1,5 @@
1
1
  module Granite
2
2
  module Form
3
- VERSION = '0.1.0'.freeze
3
+ VERSION = '0.1.1'.freeze
4
4
  end
5
5
  end
@@ -126,13 +126,25 @@ describe Granite::Form::Model::Representation do
126
126
 
127
127
  specify do
128
128
  expect { post.validate }.to change { post.errors.messages }
129
- .to(hash_including('author.user.email': ['is invalid'], name: ["can't be blank"]))
129
+ .to('author.user.email': ['is invalid'], name: ["can't be blank"])
130
130
  end
131
131
 
132
132
  if ActiveModel.version >= Gem::Version.new('6.1.0')
133
133
  specify do
134
134
  expect { post.validate }.to change { post.errors.details }
135
- .to(hash_including('author.user.email': [{error: 'is invalid'}], name: [{error: :blank}]))
135
+ .to('author.user.email': [{error: 'is invalid'}], name: [{error: :blank}])
136
+ end
137
+ end
138
+
139
+ context 'when using symbol in error message of represented model' do
140
+ before do
141
+ Author.validates :name, inclusion: {in: ['Author'], message: :invalid_name, allow_blank: true}
142
+ post.author.name = 'Not Author'
143
+ end
144
+
145
+ specify do
146
+ expect { post.validate }.to change { post.errors.messages }
147
+ .to('author.user.email': ['is invalid'], name: ['must be Author'])
136
148
  end
137
149
  end
138
150
  end
data/spec/spec_helper.rb CHANGED
@@ -8,8 +8,7 @@ require 'rack/test'
8
8
  require 'action_controller/metal/strong_parameters'
9
9
  require 'database_cleaner'
10
10
 
11
- require 'support/model_helpers'
12
- require 'support/muffle_helper'
11
+ Dir[File.join(__dir__, 'support', '**', '*.rb')].sort.each { |f| require f }
13
12
 
14
13
  ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
15
14
  ActiveRecord::Base.logger = Logger.new('/dev/null')
@@ -0,0 +1,6 @@
1
+ I18n.backend.store_translations(:en, YAML.safe_load(<<-YAML))
2
+ activerecord:
3
+ errors:
4
+ messages:
5
+ invalid_name: "must be Author"
6
+ YAML
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: granite-form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - pyromaniac
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-21 00:00:00.000000000 Z
11
+ date: 2022-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -200,6 +200,7 @@ extensions: []
200
200
  extra_rdoc_files: []
201
201
  files:
202
202
  - ".codeclimate.yml"
203
+ - ".github/CODEOWNERS"
203
204
  - ".github/workflows/ci.yml"
204
205
  - ".github/workflows/main.yml"
205
206
  - ".gitignore"
@@ -331,6 +332,7 @@ files:
331
332
  - spec/spec_helper.rb
332
333
  - spec/support/model_helpers.rb
333
334
  - spec/support/muffle_helper.rb
335
+ - spec/support/translations.rb
334
336
  homepage: ''
335
337
  licenses: []
336
338
  metadata: {}
@@ -401,3 +403,4 @@ test_files:
401
403
  - spec/spec_helper.rb
402
404
  - spec/support/model_helpers.rb
403
405
  - spec/support/muffle_helper.rb
406
+ - spec/support/translations.rb