schemattr 0.1.0 → 0.2.0

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: 4d2d2b02fcfc5238afd51f0741a619f334315e785b91c2add642cc1ef0955962
4
- data.tar.gz: b586cd63d36d773027f6786b81c785eba67b4439a1f9999140e7bff4ad44eb4d
3
+ metadata.gz: 1ed48f215b1651cfcaca945564ee28889209196633128c453c25050c93948092
4
+ data.tar.gz: 1d93e1999e211d8168b2f1dea9bb650043afe606a0c6c2eeb006689a6f4184eb
5
5
  SHA512:
6
- metadata.gz: 6bd7afaa4e360c1efe3b171fe2815f2687c23aaf6f1243bdb162ad720788ffd531b2569bfc63e16cd35698a0ad52fdc80196518703651c02d4e7251fe985a59c
7
- data.tar.gz: a59b2bd4c1f0bc29ba27d0859512fd863208f4b7591d4a951e67b60e2f80c4a6053fbd61b0598ef264798249ae84c3df4d51591ff9c18f24cc88ec23daee7bb3
6
+ metadata.gz: e38303d1c00e993a70b4f64dd37287aef23b3eac18a4a233482adc01e9ed90714a71b50128208eb8f46ec26d2e0c5e7c965470cf9e4cbd7b328a663ca0492f6e
7
+ data.tar.gz: 43361ee53cabc37ca4f3e538cf93d1fb4328584e4564e0230cb7a352a375d59895c7ca9503fa71e3287638490780bc7cd0b80de1fd56a40ffbfc0f2a311fd302
data/CHANGELOG.md ADDED
File without changes
@@ -1,6 +1,4 @@
1
- Copyright 2019 Jeremy Jackson
2
-
3
- https://github.com/jejacks0n/schemattr
1
+ Copyright 2023 Jeremy Jackson
4
2
 
5
3
  Permission is hereby granted, free of charge, to any person obtaining
6
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,16 +1,19 @@
1
- Schemattr
2
- =========
1
+ # Schemattr - Schema-ish ActiveRecord attributes
3
2
 
4
- [![Gem Version](https://img.shields.io/gem/v/schemattr.svg)](http://badge.fury.io/rb/schemattr)
5
- [![Build Status](https://img.shields.io/travis/jejacks0n/schemattr.svg)](https://travis-ci.org/jejacks0n/schemattr)
6
- [![Code Climate](https://codeclimate.com/github/jejacks0n/schemattr/badges/gpa.svg)](https://codeclimate.com/github/jejacks0n/schemattr)
7
- [![Test Coverage](https://codeclimate.com/github/jejacks0n/schemattr/badges/coverage.svg)](https://codeclimate.com/github/jejacks0n/schemattr)
8
- [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
3
+ <img alt="Shemattr" width="150" height="144" src="https://user-images.githubusercontent.com/13765/255353418-61285561-09cf-4208-8dd5-c00455e4288a.png" align="right" hspace="20">
4
+
5
+ [![Gem Version](https://img.shields.io/gem/v/schemattr.svg?label=gem%20version)](https://rubygems.org/gems/schemattr)
6
+ [![MIT License](https://img.shields.io/github/license/jejacks0n/schemattr.svg)](https://opensource.org/licenses/MIT)
7
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/jejacks0n/schemattr/ci.yml.svg?label=build%20status)](https://github.com/jejacks0n/schemattr/actions/workflows/ci.yml)
8
+ [![Maintainability](https://img.shields.io/codeclimate/coverage-letter/jejacks0n/schemattr.svg?label=maintainability)](https://codeclimate.com/github/jejacks0n/schemattr/maintainability)
9
+ [![Test Coverage](https://img.shields.io/codeclimate/coverage/jejacks0n/schemattr.svg?label=test%20coverage)](https://codeclimate.com/github/jejacks0n/schemattr/test_coverage)
10
+ [![RubyGems](https://img.shields.io/gem/dt/schemattr.svg?label=rubygems%20downloads)](https://rubygems.org/gems/schemattr)
9
11
 
10
12
  Schemattr is an ActiveRecord extension that provides a helpful schema-less attribute DSL. It can be used to define a
11
13
  simple schema for a single attribute that can change over time without having to migrate existing data.
12
14
 
13
15
  ### Background
16
+
14
17
  Let's say you have a User model, and that model has a simple concept of settings -- just one for now. It's a boolean
15
18
  named `opted_in`, and it means that the user is opted in to receive email updates. Sweet, we go add a migration for this
16
19
  setting and migrate. Ship it, we're done with that feature.
@@ -32,19 +35,33 @@ methods, can keep a real column synced with one if its fields, and more.
32
35
  If you're using Schemattr and want to add a new setting field, it's as simple as adding a new field to the attribute
33
36
  schema and setting a default right there in the code. No migrations, no hassles, easy deployment.
34
37
 
35
- ## Installation
38
+ ## Download and Installation
39
+
40
+ Add this line to your Gemfile:
41
+
36
42
  ```ruby
37
43
  gem "schemattr"
38
44
  ```
39
45
 
46
+ Or install the latest version with RubyGems:
47
+
48
+ ```bash
49
+ gem install schemattr
50
+ ```
51
+
52
+ Source code can be downloaded as part of the project on GitHub:
53
+
54
+ * https://github.com/jejacks0n/schemattr
55
+
40
56
  ## Usage
57
+
41
58
  In the examples we assume there's already a User model and table.
42
59
 
43
60
  First, let's create a migration to add your schema-less attribute. In postgres you can use a JSON column. We use the
44
61
  postgres JSON type as our example because the JSON type allows queries and indexing, and hstore does annoying things to
45
62
  booleans. We don't need to set our default value to an empty object because Schemattr handles that for us.
46
63
 
47
- *Note*: If you're using a different database provider, like sqlite3 for instance, you can use a text column and tell
64
+ _Note_: If you're using a different database provider, like sqlite3 for instance, you can use a text column and tell
48
65
  ActiveRecord to serialize that column (e.g. `serialize :settings` in your model). Though, you won't be able to easily
49
66
  query in these cases so consider your options.
50
67
 
@@ -75,8 +92,8 @@ Notice that we've done nothing else, but we already have a working version of wh
75
92
  ```
76
93
  user = User.new
77
94
  user.settings.opted_in? # => true
78
- user.settings.email_group_advanced? # => false
79
- user.settings.email_group_expert? # => false
95
+ user.settings.email_group_advanced? # => false
96
+ user.settings.email_group_expert? # => false
80
97
  ```
81
98
 
82
99
  If we save the user at this point, these settings will be persisted. We can also make changes to them at this point, and
@@ -84,27 +101,30 @@ when they're persisted they'll include whatever we've changed them to be. If we
84
101
  they'll just be the defaults if we ever ask again.
85
102
 
86
103
  ### Field types
104
+
87
105
  The various field types are outlined below. When you define a string field for instance, the value will be coerced into
88
106
  a string at the time that it's set.
89
107
 
90
- type | description
91
- ---------|--------------
92
- boolean | boolean value
93
- string | string value
94
- text | same as string type
95
- integer | number value
96
- bigint | same as integer
97
- float | floating point number value
98
- decimal | same as float
99
- datetime | datetime object
100
- time | time object (stored the same as datetime)
101
- date | date object
108
+ | type | description |
109
+ |----------|-------------------------------------------|
110
+ | boolean | boolean value |
111
+ | string | string value |
112
+ | text | same as string type |
113
+ | integer | number value |
114
+ | bigint | same as integer |
115
+ | float | floating point number value |
116
+ | decimal | same as float |
117
+ | datetime | datetime object |
118
+ | time | time object (stored the same as datetime) |
119
+ | date | date object |
120
+ | hash | hash object |
102
121
 
103
122
  You can additionally define your own types using `field :foo, :custom_type` and there will no coercion at the time the
104
123
  field is set -- this is intended for when you need something that doesn't care what type it is. This generally makes it
105
124
  harder to use in forms however.
106
125
 
107
126
  ### Delegating
127
+
108
128
  If you don't like the idea of having to access these attributes at `user.settings` you can specify that you'd like them
109
129
  delegated. This adds delegation of the methods that exist on settings to the User instances.
110
130
 
@@ -122,10 +142,11 @@ user.opted_in? # => false
122
142
  ```
123
143
 
124
144
  ### Strict mode vs. arbitrary fields
145
+
125
146
  By default, Schemattr doesn't allow arbitrary fields to be added, but it supports it. When strict mode is disabled, it
126
147
  allows any arbitrary field to be set or asked for.
127
148
 
128
- *Note*: When delegated and strict mode is disabled, you cannot set arbitrary fields on the model directly and must
149
+ _Note_: When delegated and strict mode is disabled, you cannot set arbitrary fields on the model directly and must
129
150
  access them through the attribute that you've defined -- in our case, it's `settings`.
130
151
 
131
152
  ```ruby
@@ -143,6 +164,7 @@ user.foo # => NoMethodError
143
164
  ```
144
165
 
145
166
  ### Overriding
167
+
146
168
  Schemattr provides the ability to specify your own attribute class. By doing so you can provide your own getters and
147
169
  setters and do more complex logic. In this example we're providing the inverse of `opted_in` with an `opted_out` psuedo
148
170
  field.
@@ -153,7 +175,7 @@ class UserSettings < Schemattr::Attribute
153
175
  !self[:opted_in]
154
176
  end
155
177
  alias_method :opted_out, :opted_out?
156
-
178
+
157
179
  def opted_out=(val)
158
180
  self.opted_in = !val
159
181
  end
@@ -178,6 +200,7 @@ Our custom `opted_out` psuedo field won't be persisted, because it's not a defin
178
200
  existing field that is persisted (`opted_in`).
179
201
 
180
202
  #### Getters and setters
203
+
181
204
  When overriding the attribute class with your own, you can provide your own custom getters and setters as well. These
182
205
  will not be overridden by whatever Schemattr thinks they should do. Take this example, where when someone turns on or
183
206
  off a setting we want to subscribe/unsubscribe them to an email list via a third party.
@@ -196,9 +219,10 @@ class UserSettings < Schemattr::Attribute
196
219
  end
197
220
  ```
198
221
 
199
- *Note*: This is not a real world scenario but serves our purposes of describing an example.
222
+ _Note_: This is not a real world scenario but serves our purposes of describing an example.
200
223
 
201
224
  ### Renaming fields
225
+
202
226
  Schemattr makes it easy to rename fields as well. Let's say you've got a field named `opted_in`, as the examples have
203
227
  shown thus far. But you've added new email lists, and you think `opted_in` is too vague. Like, opted in for what?
204
228
 
@@ -207,14 +231,16 @@ We can create a new field that is correctly named, and specify what attribute we
207
231
  ```ruby
208
232
  attribute_schema :settings do
209
233
  # field :opted_in, :boolean, default: true
210
- field :email_list_beginner, :boolean, from: :opted_in, default: true
234
+ field :email_list_beginner, :boolean, value_from: :opted_in, default: true
211
235
  end
212
236
  ```
213
237
 
214
- Specifying the `from: :opted_in` option will tell Schemattr to look for the value that may have already been defined in
238
+ Specifying the `value_from: :opted_in` option will tell Schemattr to look for the value that may have already been defined in
215
239
  `opted_in` before the rename. This allows for slow migrations, but you can also write a migration to ensure this happens
216
240
  quickly.
217
241
 
242
+ This previously used the keyword `from`, and this keyword is deprecated.
243
+
218
244
  ### Syncing attributes
219
245
 
220
246
  There's a down side to keeping some things internal to this settings attribute. You can query JSON types in postgres,
@@ -247,6 +273,7 @@ using things like `user.update_column(:opted_in, false)`, and `User.update_all(o
247
273
  get out of sync.
248
274
 
249
275
  ## Querying a JSON column
276
+
250
277
  This has come up a little bit, and so it's worth documenting -- though it has very little to do with Schemattr. When you
251
278
  have a JSON column in postgres, you can query values from within that column in various ways.
252
279
 
@@ -255,12 +282,17 @@ these are the common scenarios that we've used.
255
282
 
256
283
  ```
257
284
  User.where("(settings->>'opted_in')::boolean") # boolean query
258
- User.where("settings->>'string_value' = ?", "some string") # string query
285
+ User.where("settings->>'string_value' = ?", "some string") # string query
259
286
  ```
260
287
 
261
288
  ## License
262
- Licensed under the [MIT License](http://creativecommons.org/licenses/MIT/)
263
289
 
264
- Copyright 2019 [jejacks0n](https://github.com/jejacks0n)
290
+ This project is released under the MIT license:
291
+
292
+ * https://opensource.org/licenses/MIT
293
+
294
+ Copyright 2023 [jejacks0n](https://github.com/jejacks0n)
265
295
 
266
296
  ## Make Code Not War
297
+
298
+ [![forthebadge](http://forthebadge.com/images/badges/built-with-love.svg)](http://forthebadge.com)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Schemattr
2
4
  module ActiveRecordExtension
3
5
  module ClassMethods
@@ -38,7 +40,6 @@ module Schemattr
38
40
  end
39
41
 
40
42
  private
41
-
42
43
  def schemaless_attributes
43
44
  @_schemaless_attributes ||= {}
44
45
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Schemattr
2
4
  class Attribute
3
5
  attr_accessor :model, :attr_name, :hash
@@ -22,7 +24,6 @@ module Schemattr
22
24
  end
23
25
 
24
26
  private
25
-
26
27
  def method_missing(m, *args)
27
28
  if @allow_arbitrary_attributes
28
29
  self[$1] = args[0] if args.length == 1 && /^(\w+)=$/ =~ m
data/lib/schemattr/dsl.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Schemattr
2
4
  class DSL
3
5
  attr_accessor :attribute_class, :delegated, :defaults
@@ -13,8 +15,12 @@ module Schemattr
13
15
  end
14
16
 
15
17
  protected
16
-
17
18
  def field(name, type, options = {})
19
+ if options[:from].present?
20
+ options[:value_from] = options.delete(:from)
21
+ log_warning(name, type, options[:value_from])
22
+ end
23
+
18
24
  if respond_to?(type, true)
19
25
  send(type, name, options)
20
26
  else
@@ -55,10 +61,9 @@ module Schemattr
55
61
  alias_method :time, :datetime
56
62
 
57
63
  private
58
-
59
64
  def define(name, boolean, options, blocks = {})
60
65
  setter = blocks[:setter] || lambda { sync_value(self[name] = val, options[:sync]) }
61
- getter = blocks[:getter] || lambda { migrate_value(self[name], options[:from]) }
66
+ getter = blocks[:getter] || lambda { migrate_value(self[name], options[:value_from]) }
62
67
  default_for(name, options[:default])
63
68
  method_for("#{name}=", options[:sync], &setter)
64
69
  method_for(name, options[:sync], &getter)
@@ -69,6 +74,14 @@ module Schemattr
69
74
  @defaults[name.to_s] = default
70
75
  end
71
76
 
77
+ def log_warning(name, type, old_name)
78
+ message = <<-HEREDOC
79
+ Schemattr Warning: #{name}, #{type}, from: #{old_name}
80
+ You are using the keyword `from:` instead of the new `value_from:`. This is deprecated and will be removed in a future version."
81
+ HEREDOC
82
+ puts message
83
+ end
84
+
72
85
  def method_for(name, delegated = false, &block)
73
86
  @delegated.push(name.to_s) if delegated
74
87
  unless attribute_class.instance_methods.include?(name.to_sym)
@@ -1,3 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Schemattr
2
- VERSION = "0.1.0"
4
+ # Returns the currently loaded version as a +Gem::Version+.
5
+ def self.version
6
+ Gem::Version.new(VERSION::STRING)
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 0
11
+ MINOR = 2
12
+ TINY = 0
13
+ PRE = nil
14
+
15
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
+ end
3
17
  end
data/lib/schemattr.rb CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "schemattr/version"
2
4
  require "schemattr/dsl"
3
5
  require "schemattr/attribute"
4
- require "schemattr/active_record_extension.rb"
6
+ require "schemattr/active_record_extension"
5
7
 
6
8
  ActiveRecord::Base.send(:include, Schemattr::ActiveRecordExtension) if defined?(ActiveRecord)
metadata CHANGED
@@ -1,52 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schemattr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
- - jejacks0n
8
- autorequire:
7
+ - Jeremy Jackson
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-14 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2023-07-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.0.0
13
27
  description: Write schema-less attributes in ActiveRecord using a helpful and flexible
14
28
  DSL.
15
- email:
16
- - jejacks0n@gmail.com
29
+ email: jejacks0n@gmail.com
17
30
  executables: []
18
31
  extensions: []
19
32
  extra_rdoc_files: []
20
33
  files:
21
- - MIT.LICENSE
34
+ - CHANGELOG.md
35
+ - MIT-LICENSE
22
36
  - README.md
23
37
  - lib/schemattr.rb
24
38
  - lib/schemattr/active_record_extension.rb
25
39
  - lib/schemattr/attribute.rb
26
40
  - lib/schemattr/dsl.rb
27
41
  - lib/schemattr/version.rb
28
- homepage: http://github.com/jejacks0n/bitbot
42
+ homepage: https://github.com/jejacks0n/schemattr
29
43
  licenses:
30
44
  - MIT
31
- metadata: {}
32
- post_install_message:
45
+ metadata:
46
+ homepage_uri: https://github.com/jejacks0n/schemattr
47
+ source_code_uri: https://github.com/jejacks0n/schemattr
48
+ bug_tracker_uri: https://github.com/jejacks0n/schemattr/issues
49
+ changelog_uri: https://github.com/jejacks0n/schemattr/CHANGELOG.md
50
+ documentation_uri: https://github.com/jejacks0n/schemattr/README.md
51
+ rubygems_mfa_required: 'true'
52
+ post_install_message:
33
53
  rdoc_options: []
34
54
  require_paths:
35
55
  - lib
36
56
  required_ruby_version: !ruby/object:Gem::Requirement
37
57
  requirements:
38
- - - "~>"
58
+ - - ">="
39
59
  - !ruby/object:Gem::Version
40
- version: '2.4'
60
+ version: 2.7.0
41
61
  required_rubygems_version: !ruby/object:Gem::Requirement
42
62
  requirements:
43
63
  - - ">="
44
64
  - !ruby/object:Gem::Version
45
65
  version: '0'
46
66
  requirements: []
47
- rubyforge_project:
48
- rubygems_version: 2.7.6
49
- signing_key:
67
+ rubygems_version: 3.4.14
68
+ signing_key:
50
69
  specification_version: 4
51
- summary: 'Schemattr: Simple schema-less column definitions for ActiveRecord'
70
+ summary: 'Schemattr: Simple schema-less column definitions for ActiveRecord.'
52
71
  test_files: []