attribeauty 0.4.7 → 0.4.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +236 -130
- data/attribeauty.gemspec +36 -0
- data/lib/attribeauty/base.rb +6 -2
- data/lib/attribeauty/params.rb +3 -0
- data/lib/attribeauty/validator.rb +3 -3
- data/lib/attribeauty/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b6b12bbaf3cc5bbef6bd67f9d8c69ad35ba2608bd3c90798ef6510884940cb7
|
4
|
+
data.tar.gz: 2f86805ee0ca65397f78eab60e83cd2740e4eef03879f130679d062d996f0467
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68bc689b886c754315b5b41203e67fb4ed9e46818eebc8b7e4cf336c4cae0fba92b56c57ff78a2611814db61c170980ba025bcf8ff5d9b65cb22b75a59389218
|
7
|
+
data.tar.gz: 8b023ec357bd89dabfcb17ecd317bd70e322ae822a10dc17ac0aacee49465ea33b47b2efee5cf44575fc78b87fb2444cece241f49e6a320e84feb363eac33f89
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,150 +1,170 @@
|
|
1
1
|
# Attribeauty
|
2
2
|
|
3
|
-
|
4
|
-
There are so many of these (notably rails Attributes api), but none were what I wanted.
|
3
|
+
## Params
|
5
4
|
|
6
|
-
|
5
|
+
`Attribeauty::Params` casts your params and removes elements you want to exclude if they are nil or empty.
|
7
6
|
|
8
|
-
|
7
|
+
#### Why is this needed?
|
9
8
|
|
10
|
-
|
9
|
+
`params` arrive in your controllers as strings—whether they represent integers, nil, dates, or anything else. Rails handles coercion at the Model level when these params are assigned as attributes. However, there are often many steps before your params are assigned. `Attribeauty::Params` elegantly ensures that your attributes start in their expected state before continuing their journey to their final destination.
|
11
10
|
|
12
|
-
|
11
|
+
#### Directions
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
## Base
|
17
|
-
|
18
|
-
Inherit from `Attribeauty::Base` and then add attribute with the type you want.
|
19
|
-
Initialize with these and they will be cast to that attribute.
|
20
|
-
Use `assign_attributes` to update the object.
|
13
|
+
First, let's set a `params_filter` object to accept rails `params.to_unsafe_h` in the `ApplicationController`
|
21
14
|
|
15
|
+
```ruby
|
16
|
+
# app/controllers/application_controller.rb
|
17
|
+
class ApplicationController
|
18
|
+
private
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
attribute :second, :integer
|
27
|
-
attribute :third, :float
|
28
|
-
attribute :forth, :boolean
|
29
|
-
attribute :fifth, :time
|
30
|
-
attribute :sixth, :koala
|
20
|
+
def params_filter
|
21
|
+
Attribeauty::Params.with(params.to_unsafe_h)
|
22
|
+
end
|
31
23
|
end
|
32
|
-
|
33
|
-
instance = MyClass.new(first: 456)
|
34
|
-
instance.first # => "456"
|
35
|
-
instance.assign_attributes(second: "456")
|
36
|
-
instance.second # => 456
|
37
|
-
instance.first = 9000
|
38
|
-
instance.first # => "9000"
|
39
24
|
```
|
40
25
|
|
41
|
-
|
42
|
-
|
26
|
+
The `params_filter` object here will take any ruby hash, `symbolize` the keys, and is now ready for the structure you want to provide.
|
27
|
+
|
28
|
+
If a users controller receives the following params:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
{
|
32
|
+
'user' => {
|
33
|
+
'username' => 'js_bach',
|
34
|
+
'full_name' => 'Johann Sebastian Bach',
|
35
|
+
'job_title' => 'Composer',
|
36
|
+
'age' => '43',
|
37
|
+
'salary' => nil,
|
38
|
+
'email' => {
|
39
|
+
'address' => 'js@bach.music'
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
43
|
```
|
44
|
-
Attribeauty.configure do |config|
|
45
|
-
config.types[:koala] = MyTypes::Koala
|
46
|
-
end
|
47
44
|
|
48
|
-
|
49
|
-
class Koala
|
50
|
-
def cast(value)
|
51
|
-
value.inspect.to_s << "_koalas"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
45
|
+
We can coerce them with into `create_params` with the following:
|
55
46
|
|
56
|
-
class MyClass < Attribeauty::Base
|
57
|
-
attribute :wild_animal, :koala
|
58
|
-
end
|
59
47
|
|
60
|
-
|
61
|
-
|
48
|
+
```ruby
|
49
|
+
# app/controllers/my_controller.rb
|
50
|
+
class UsersController < ApplicationController
|
51
|
+
def edit; end
|
62
52
|
|
63
|
-
|
53
|
+
def update
|
54
|
+
@user = Users::Creator.call(create_params)
|
64
55
|
|
65
|
-
|
66
|
-
|
67
|
-
|
56
|
+
if @user.valid?
|
57
|
+
redirect_to index_path, notice: 'Welcome to the app'
|
58
|
+
else
|
59
|
+
flash[:alert] = @user.errors.full_messages
|
60
|
+
render :edit
|
61
|
+
end
|
62
|
+
end
|
68
63
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
64
|
+
private
|
65
|
+
|
66
|
+
def create_params
|
67
|
+
params_filter.accept do
|
68
|
+
root :user do
|
69
|
+
attribute :username, :string, required: true
|
70
|
+
attribute :full_name, :string
|
71
|
+
attribute :job_title, :string, exclude_if: [:nil?, :empty?]
|
72
|
+
attribute :age, :integer
|
73
|
+
attribute :salary, :integer, exclude_if: :nil?
|
74
|
+
attribute :email do
|
75
|
+
attribute :address, :string, required: true
|
76
|
+
attribute :receive_updates, :boolean, default: false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
78
80
|
end
|
79
81
|
end
|
80
|
-
|
81
82
|
```
|
82
83
|
|
83
|
-
|
84
|
+
The above will return a hash with the `age` integer cast to integer, the `salary` removed, and a `receive_updates` defaulted to `false`. The `root` `user` node will be removed too. If you wish to keep the root node, simply using `attribute` with a `block` will suffice. Below is the output from this:
|
84
85
|
|
85
|
-
Experimental params sanitizer is now available. This will cast your params, and remove elements you want to exclude if `nil` or `empty`
|
86
86
|
|
87
|
-
|
87
|
+
```ruby
|
88
|
+
{
|
89
|
+
'username' => 'js_bach',
|
90
|
+
'full_name' => 'Johann Sebastian Bach',
|
91
|
+
'job_title' => 'Composer',
|
92
|
+
'age' => 43,
|
93
|
+
'email' => {
|
94
|
+
'address' => 'js@bach.music',
|
95
|
+
'receive_updates' => false
|
96
|
+
}
|
97
|
+
}
|
88
98
|
|
89
99
|
```
|
90
|
-
# app/controllers/my_controller.rb
|
91
|
-
class MyController
|
92
|
-
def update
|
93
|
-
MyRecord.update(update_params)
|
94
|
-
|
95
|
-
redirect_to index_path
|
96
|
-
end
|
97
100
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
101
|
+
`Attribeauty::Params` can handle nested arrays and nested hashes with the same `accept`:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
# {
|
105
|
+
# "username" => "js_bach",
|
106
|
+
# "full_name" => "Johann Sebastian Bach",
|
107
|
+
# "job_title" => "Composer",
|
108
|
+
# "age" => 43,
|
109
|
+
# "email" => [
|
110
|
+
# { "address" => "js@bach.music", "secondary" => false },
|
111
|
+
# { "address" => "papa@bach.music", "secondary" => true }
|
112
|
+
# ]
|
113
|
+
# }
|
114
|
+
#
|
115
|
+
# or
|
116
|
+
#
|
117
|
+
# {
|
118
|
+
# "username" => "js_bach",
|
119
|
+
# "full_name" => "Johann Sebastian Bach",
|
120
|
+
# "job_title" => "Composer",
|
121
|
+
# "age" => 43,
|
122
|
+
# "email" => { "address" => "js@bach.music", "secondary" => false }
|
123
|
+
# }
|
124
|
+
def create_params
|
105
125
|
params_filter.accept do
|
106
|
-
attribute :
|
126
|
+
attribute :username, :string, required: true
|
127
|
+
attribute :full_name, :string
|
128
|
+
attribute :job_title, :string, exclude_if: [:nil?, :empty?]
|
129
|
+
attribute :age, :integer
|
130
|
+
attribute :salary, :integer, exclude_if: :nil?
|
107
131
|
attribute :email do
|
108
|
-
attribute :address, :string
|
109
|
-
attribute :
|
110
|
-
attribute :ip_address, :string, exclude_if: :empty?
|
132
|
+
attribute :address, :string, required: true
|
133
|
+
attribute :secondary, :boolean, default: false
|
111
134
|
end
|
112
135
|
end
|
113
136
|
end
|
114
137
|
```
|
115
138
|
|
116
|
-
|
117
|
-
`exclude_if` will accept a single method call (`:nil?`) or an array (`[:nil?, :empty?]`)
|
139
|
+
#### Error handling
|
118
140
|
|
119
|
-
|
141
|
+
`Attribeauty::Params` has rudimentary error handling, and will return an errors array when `required: true` values are missing:
|
142
|
+
|
143
|
+
```ruby
|
120
144
|
class MyController
|
145
|
+
def edit; end
|
146
|
+
|
121
147
|
def update
|
122
|
-
|
123
|
-
|
124
|
-
|
148
|
+
if params_filter.errors.any?
|
149
|
+
flash[:alert] = params.errors.join(', ')
|
150
|
+
render :edit
|
151
|
+
else
|
152
|
+
MyRecord::Updater.call(update_params)
|
153
|
+
redirect_to index_path
|
154
|
+
end
|
125
155
|
end
|
126
156
|
|
127
157
|
private
|
128
158
|
|
129
|
-
#
|
130
|
-
# { user: {
|
131
|
-
|
132
|
-
|
133
|
-
Attribeauty::Params.with(request.params)
|
134
|
-
end
|
159
|
+
# with the following params:
|
160
|
+
# { user: { username: nil } }
|
161
|
+
|
162
|
+
# update_params.errors => ["username required"]
|
135
163
|
|
136
|
-
# using root will exclude the value and yield:
|
137
|
-
# { title: "woo", email: { address: "hmm@yep.com" } }
|
138
|
-
#
|
139
164
|
def update_params
|
140
165
|
params_filter.accept do
|
141
166
|
root :user do
|
142
|
-
attribute :
|
143
|
-
attribute :email do
|
144
|
-
attribute :address, :string, exclude_if: [:empty?, :nil?]
|
145
|
-
attribute :valid, :boolean
|
146
|
-
attribute :ip_address, :string, exclude_if: :empty?
|
147
|
-
end
|
167
|
+
attribute :username, :string, required: true
|
148
168
|
end
|
149
169
|
end
|
150
170
|
end
|
@@ -152,38 +172,30 @@ end
|
|
152
172
|
|
153
173
|
```
|
154
174
|
|
175
|
+
#### Raising Errors
|
176
|
+
|
155
177
|
If you want to raise an error, rather than just return the errors in an array, use the `accept!` method. Will raise `Attribeauty::MissingAttributeError` with the required elements:
|
156
178
|
|
157
179
|
|
158
|
-
```
|
180
|
+
```ruby
|
159
181
|
class MyController
|
160
182
|
def update
|
161
|
-
MyRecord.
|
162
|
-
|
183
|
+
MyRecord::Updater.call(update_params)
|
184
|
+
# calling update_params
|
185
|
+
# will raise: Attribeauty::MissingAttributeError, "username required"
|
186
|
+
|
163
187
|
redirect_to index_path
|
164
188
|
end
|
165
189
|
|
166
190
|
private
|
167
191
|
|
168
|
-
#
|
169
|
-
# { user: {
|
170
|
-
#
|
171
|
-
def params_filter
|
172
|
-
Attribeauty::Params.with(request.params)
|
173
|
-
end
|
192
|
+
# with the following params:
|
193
|
+
# { user: { username: nil } }
|
174
194
|
|
175
|
-
# This following with the accept! method
|
176
|
-
# will raise: Attribeauty::MissingAttributeError, "title required, email required"
|
177
|
-
#
|
178
195
|
def update_params
|
179
196
|
params_filter.accept! do
|
180
197
|
root :user do
|
181
|
-
attribute :
|
182
|
-
attribute :email do
|
183
|
-
attribute :address, :string
|
184
|
-
attribute :valid, :boolean
|
185
|
-
attribute :ip_address, :string
|
186
|
-
end
|
198
|
+
attribute :username, :string, required: true
|
187
199
|
end
|
188
200
|
end
|
189
201
|
end
|
@@ -191,10 +203,12 @@ end
|
|
191
203
|
|
192
204
|
```
|
193
205
|
|
194
|
-
|
195
|
-
You can also exclude a value from this by useing the `allows` option.
|
206
|
+
#### Require all
|
196
207
|
|
197
|
-
|
208
|
+
What if you want to require all attributes? If you pass the `required: true` or `exclude_if: :nil?` with the `accept`, it will be applied to all attributes.
|
209
|
+
You can also exclude a value from this by using the `allows` option.
|
210
|
+
|
211
|
+
```ruby
|
198
212
|
class MyController
|
199
213
|
def update
|
200
214
|
MyRecord.update(update_params)
|
@@ -204,17 +218,13 @@ class MyController
|
|
204
218
|
|
205
219
|
private
|
206
220
|
|
207
|
-
#
|
221
|
+
# with the following params:
|
208
222
|
# { user: { profile: [{ address: { street_name: "Main St" } }] } }
|
209
|
-
#
|
210
|
-
def params_filter
|
211
|
-
Attribeauty::Params.with(request.params)
|
212
|
-
end
|
213
223
|
|
214
|
-
#
|
215
|
-
|
224
|
+
# required: true will be passed onto all attributes, except ip_address
|
225
|
+
|
216
226
|
def update_params
|
217
|
-
params_filter.accept
|
227
|
+
params_filter.accept required: true do
|
218
228
|
root :user do
|
219
229
|
attribute :title, :string,
|
220
230
|
attribute :email do
|
@@ -232,6 +242,102 @@ end
|
|
232
242
|
See `test/test_params.rb` for more examples
|
233
243
|
|
234
244
|
|
245
|
+
## Base
|
246
|
+
|
247
|
+
I needed a straightforward way to initialize mutable objects, and this solution provides exactly that. While there are many existing options (notably the Rails Attributes API), I opted to build my own.
|
248
|
+
|
249
|
+
|
250
|
+
Inherit from `Attribeauty::Base` and then add attribute with the type you want.
|
251
|
+
Initialize with these and they will be cast to that attribute.
|
252
|
+
Use `assign_attributes` to update the object.
|
253
|
+
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
class MyClass < Attribeauty::Base
|
257
|
+
attribute :first, :string
|
258
|
+
attribute :second, :integer
|
259
|
+
attribute :third, :float
|
260
|
+
attribute :forth, :boolean
|
261
|
+
attribute :fifth, :time
|
262
|
+
attribute :sixth, :koala
|
263
|
+
attribute :seventh, :string, default: "Kangaroo"
|
264
|
+
end
|
265
|
+
|
266
|
+
instance = MyClass.new(first: 456)
|
267
|
+
instance.first # => "456"
|
268
|
+
instance.assign_attributes(second: "456")
|
269
|
+
instance.second # => 456
|
270
|
+
instance.first = 9000
|
271
|
+
instance.first # => "9000"
|
272
|
+
instance.seventh # => "Kangaroo"
|
273
|
+
```
|
274
|
+
|
275
|
+
To add your own types, simply have a class that handles `MyClassName.new.cast(value)`:
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
Attribeauty.configure do |config|
|
279
|
+
config.types[:koala] = MyTypes::Koala
|
280
|
+
end
|
281
|
+
|
282
|
+
module MyTypes
|
283
|
+
class Koala
|
284
|
+
def cast(value)
|
285
|
+
value.inspect.to_s << "_koalas"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
class MyClass < Attribeauty::Base
|
291
|
+
attribute :wild_animal, :koala
|
292
|
+
end
|
293
|
+
|
294
|
+
instance = MyClass.new(wild_animal: "the_wildest_animals_are")
|
295
|
+
instance.wild_animal # => "the_wildest_animals_are_koalas"
|
296
|
+
|
297
|
+
```
|
298
|
+
|
299
|
+
To use rails types add to your config:
|
300
|
+
```ruby
|
301
|
+
# config/initializers/attribeauty.rb
|
302
|
+
|
303
|
+
Rails.application.reloader.to_prepare do
|
304
|
+
Attribeauty.configure do |config|
|
305
|
+
config.types[:string] = ActiveModel::Type::String
|
306
|
+
config.types[:boolean] = ActiveModel::Type::Boolean
|
307
|
+
config.types[:date] = ActiveModel::Type::Date
|
308
|
+
config.types[:time] = ActiveModel::Type::Time
|
309
|
+
config.types[:datetime] = ActiveModel::Type::DateTime
|
310
|
+
config.types[:float] = ActiveModel::Type::Float
|
311
|
+
config.types[:integer] = ActiveModel::Type::Integer
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
```
|
316
|
+
|
317
|
+
#### Is this for rails only?
|
318
|
+
Nope, any ruby program will work with this.
|
319
|
+
|
320
|
+
## Installation
|
321
|
+
|
322
|
+
Add `attribeauty` to your application's Gemfile and `bundle install` the gem:
|
323
|
+
|
324
|
+
```ruby
|
325
|
+
# Gemfile
|
326
|
+
gem 'attribeauty'
|
327
|
+
```
|
328
|
+
|
329
|
+
Use bundle to automatically install the gem and add to the application's Gemfile by executing:
|
330
|
+
|
331
|
+
```bash
|
332
|
+
$ bundle add attribeauty
|
333
|
+
```
|
334
|
+
|
335
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
336
|
+
|
337
|
+
```bash
|
338
|
+
$ gem install attribeauty
|
339
|
+
```
|
340
|
+
|
235
341
|
## Development
|
236
342
|
|
237
343
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/attribeauty.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/attribeauty/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "attribeauty"
|
7
|
+
spec.version = Attribeauty::VERSION
|
8
|
+
spec.authors = ["Toby"]
|
9
|
+
spec.email = ["toby@darkroom.tech"]
|
10
|
+
|
11
|
+
spec.summary = "Attributes simply done"
|
12
|
+
spec.description = "There are so many of these, I just needed this one."
|
13
|
+
spec.homepage = "https://github.com/tobyond/attribeauty"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 3.2.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/tobyond/attribeauty"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(__dir__) do
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
(File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
# Uncomment to register a new dependency of your gem
|
32
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
33
|
+
|
34
|
+
# For more information and examples about making a new gem, check out our
|
35
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
36
|
+
end
|
data/lib/attribeauty/base.rb
CHANGED
@@ -4,14 +4,18 @@ module Attribeauty
|
|
4
4
|
# base class to inherit from
|
5
5
|
# class MyClass < Attribeauty::Base
|
6
6
|
class Base
|
7
|
-
def self.attribute(name, type)
|
7
|
+
def self.attribute(name, type, **args)
|
8
8
|
@attributes ||= {}
|
9
9
|
return if @attributes[name]
|
10
10
|
|
11
11
|
@attributes[name] = type
|
12
12
|
|
13
13
|
class_eval(<<-CODE, __FILE__, __LINE__ + 1)
|
14
|
-
def #{name}=(value)
|
14
|
+
def #{name}=(value)
|
15
|
+
validator = Validator.run(#{name.inspect}, value, #{type.inspect}, #{args})
|
16
|
+
raise MissingAttributeError, validator.errors.join(', ') if validator.errors.any?
|
17
|
+
@#{name} = validator.value
|
18
|
+
end
|
15
19
|
|
16
20
|
def #{name};@#{name};end
|
17
21
|
CODE
|
data/lib/attribeauty/params.rb
CHANGED
@@ -71,6 +71,9 @@ module Attribeauty
|
|
71
71
|
# in Rails if you have a user model you can call
|
72
72
|
# Attribeauty::Params.with(params.to_unsafe_h).generate_for(User, :username, :name, :age, :email)
|
73
73
|
# It will grab the type, and add an exclude_if: for all with Null false
|
74
|
+
# Note, there are very few circumstances where you wouldn't want to just assign_attributes
|
75
|
+
# to the model, and use the types from there, but here you go.
|
76
|
+
# This api will never be tested or documented.
|
74
77
|
def generate_for(model, *columns)
|
75
78
|
raise "Method requires Rails" unless defined?(Rails)
|
76
79
|
|
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
module Attribeauty
|
4
4
|
class Validator
|
5
|
-
def self.run(name,
|
6
|
-
new(name,
|
5
|
+
def self.run(name, original_val, type = nil, args = {})
|
6
|
+
new(name, original_val, type, args).run
|
7
7
|
end
|
8
8
|
|
9
9
|
attr_reader :original_val, :errors, :name, :type, :required,
|
10
10
|
:default, :excludes, :value, :valid, :allows
|
11
11
|
|
12
|
-
def initialize(name, original_val, type = nil,
|
12
|
+
def initialize(name, original_val, type = nil, args = {})
|
13
13
|
@name = name
|
14
14
|
@type = type
|
15
15
|
@original_val = original_val
|
data/lib/attribeauty/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attribeauty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Toby
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: There are so many of these, I just needed this one.
|
14
14
|
email:
|
@@ -30,6 +30,7 @@ files:
|
|
30
30
|
- LICENSE.txt
|
31
31
|
- README.md
|
32
32
|
- Rakefile
|
33
|
+
- attribeauty.gemspec
|
33
34
|
- lib/attribeauty.rb
|
34
35
|
- lib/attribeauty/base.rb
|
35
36
|
- lib/attribeauty/configuration.rb
|