polutan 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 922efa48e9d130348c44b65161804fc2c9ec71a395e3544e37d3c7b9e96ad454
4
+ data.tar.gz: bb022c4abae1408f652ed500e6b2e73c98712bf08c3bf32fdc57f134d20c1c13
5
+ SHA512:
6
+ metadata.gz: 3af8fc24dc11ffd2d1a0847b0dd0c52f7789a7dfc91d139bd8d47c5b43cca8a944d204a7242b90ed297e179bf92fcbe1b7d6ad25e2be2a2cbbac6240d663ff3a
7
+ data.tar.gz: 69e309e2f7ceb22b2180d972d508a419a6396be4b2eca398a44b017dc243930d89bb55a47d6c4f0f2e61b70717b5c38e04d5b5f230b9c077904d97f3ef31bddc
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in cable_ready.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,81 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ polutan (1.0.0)
5
+ activeentity (~> 6.1)
6
+ kredis (~> 0.2)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activeentity (6.3.0)
12
+ activemodel (>= 6.0, < 8)
13
+ activesupport (>= 6.0, < 8)
14
+ activemodel (7.0.2.2)
15
+ activesupport (= 7.0.2.2)
16
+ activesupport (7.0.2.2)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 1.6, < 2)
19
+ minitest (>= 5.1)
20
+ tzinfo (~> 2.0)
21
+ ast (2.4.2)
22
+ coderay (1.1.3)
23
+ concurrent-ruby (1.1.9)
24
+ i18n (1.10.0)
25
+ concurrent-ruby (~> 1.0)
26
+ kredis (0.4.0)
27
+ activesupport (>= 6.0.0)
28
+ redis (~> 4.2)
29
+ magic_frozen_string_literal (1.2.0)
30
+ method_source (0.9.2)
31
+ minitest (5.15.0)
32
+ parallel (1.21.0)
33
+ parser (3.1.0.0)
34
+ ast (~> 2.4.1)
35
+ pry (0.12.2)
36
+ coderay (~> 1.1.0)
37
+ method_source (~> 0.9.0)
38
+ pry-nav (0.3.0)
39
+ pry (>= 0.9.10, < 0.13.0)
40
+ rainbow (3.1.1)
41
+ rake (13.0.6)
42
+ redis (4.6.0)
43
+ regexp_parser (2.2.1)
44
+ rexml (3.2.5)
45
+ rubocop (1.25.1)
46
+ parallel (~> 1.10)
47
+ parser (>= 3.1.0.0)
48
+ rainbow (>= 2.2.2, < 4.0)
49
+ regexp_parser (>= 1.8, < 3.0)
50
+ rexml
51
+ rubocop-ast (>= 1.15.1, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 1.4.0, < 3.0)
54
+ rubocop-ast (1.15.2)
55
+ parser (>= 3.0.1.1)
56
+ rubocop-performance (1.13.2)
57
+ rubocop (>= 1.7.0, < 2.0)
58
+ rubocop-ast (>= 0.4.0)
59
+ ruby-progressbar (1.11.0)
60
+ standard (1.7.2)
61
+ rubocop (= 1.25.1)
62
+ rubocop-performance (= 1.13.2)
63
+ standardrb (1.0.1)
64
+ standard
65
+ tzinfo (2.0.4)
66
+ concurrent-ruby (~> 1.0)
67
+ unicode-display_width (2.1.0)
68
+
69
+ PLATFORMS
70
+ ruby
71
+
72
+ DEPENDENCIES
73
+ magic_frozen_string_literal (~> 1.2.0)
74
+ polutan!
75
+ pry (~> 0.12)
76
+ pry-nav (~> 0.3)
77
+ rake (~> 13.0, >= 13.0.3)
78
+ standardrb (~> 1.0)
79
+
80
+ BUNDLED WITH
81
+ 2.1.4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Nervive Studio
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.
data/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # Polutan
2
+
3
+ The [polutan](https://github.com/nervive/polutan) gem offers Rails developers a way to **gather attributes** on an unsaved model **across multiple requests**. It's perfect for [StimulusReflex](https://docs.stimulusreflex.com/) users that are building faceted search interfaces, as well as [Optimism](https://optimism.nervive.studio/) users looking to implement real-time, per-attribute validation schemes.
4
+
5
+ Try a demo, here: 👉 [Under Line StimulusReflex](https://underline.nervive.studio/) 👈
6
+
7
+ [![GitHub stars](https://img.shields.io/github/stars/nervive/polutan?style=social)](https://github.com/nervive/polutan) [![GitHub forks](https://img.shields.io/github/forks/nervive/polutan?style=social)](https://github.com/nervive/polutan)
8
+
9
+ ## Why use Polutan?
10
+
11
+ Many reactive UI concepts are a pain in the ass to implement using the classic Rails request/response pattern, which was created at a time before developers started using Ajax to update portions of a page. ActionController is designed to mutate state in response to form submissions, leading to abuse of the session object and awkward hacks to validate and persist models across multiple requests.
12
+
13
+ Polutan presents a flexible and lightweight mechanism to refine a model that persists its attributes across multiple updates, and even multiple servers.
14
+
15
+ ## Is Polutan for you?
16
+
17
+ Do you ever find yourself:
18
+
19
+ * building complex search interfaces
20
+ * creating multi-stage data entry processes
21
+ * frustrated by the limitations of classic form submission
22
+ * wanting to save data even if the model is currently invalid
23
+ * reinventing the wheel every time you need field validation
24
+
25
+ If you answered yes to any of the above... you are every Rails developer, and you're not crazy. This functionality has been a blind-spot in the framework for a long time.
26
+
27
+ Yes, Polutan is for **you**.
28
+
29
+ ## Key features and advantages
30
+
31
+ * A natural fit with [StimulusReflex](https://docs.stimulusreflex.com/) and [Stimulus](https://stimulus.hotwire.dev/)
32
+ * No reliance on sessions, so it works across servers
33
+ * Easy to learn, quick to implement
34
+ * Supports model attributes with defaults, arrays and dirty checking
35
+ * Model validations and errors
36
+ * No need to mess around with temporary records
37
+
38
+ ## How does Polutan work?
39
+
40
+ First, set up an Polutan class that defines some [attributes](https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute). Your class will inherit from `Possibility`, which is aptly-named.
41
+
42
+ ```ruby
43
+ class ExampleModel < Possibility
44
+ attribute :name, :string
45
+ attribute :age, :integer, default: 21
46
+ end
47
+ ```
48
+
49
+ Then create an instance and assign it to an instance variable in the controller responsible for your initial page load:
50
+
51
+ ```ruby
52
+ class ExampleController < ApplicationController
53
+ def index
54
+ @af = ExampleModel.new
55
+ end
56
+ end
57
+ ```
58
+
59
+ Emit the instance id as a data attribute on every element which can update your model:
60
+
61
+ ```text
62
+ Name: <input type="text" data-af="<%= @af.id %>" data-reflex="input->Example#name" /><br/>
63
+ Age: <input type="text" data-af="<%= @af.id %>" data-reflex="input->Example#age" placeholder="<%= @id.age %>" />
64
+ ```
65
+
66
+ Since all attributes are gathered and sent to the server during a Reflex operation, it's easy to retrieve the instance id from the Reflex element accessor and use it to call up the correct Polutan object and make changes to it:
67
+
68
+ ```ruby
69
+ class ExampleReflex < ApplicationReflex
70
+ def name
71
+ model = ExampleModel.find(element.dataset.af)
72
+ model[:name] = element.value
73
+ end
74
+
75
+ def age
76
+ model = ExampleModel.find(element.dataset.af)
77
+ model[:age] = element.value
78
+ end
79
+ end
80
+ ```
81
+
82
+ The current state of the attributes is persisted every time you set the value of an attribute using bracket notation. You can use standard setter assignments, but the model state will not be persisted until you manually call `save`:
83
+
84
+ ```ruby
85
+ model[:name] = "Helen" # saved
86
+ model.name = "Helen" # not saved
87
+ model.save # saved
88
+ ```
89
+
90
+ {% hint style="warning" %}
91
+ Polutan class attributes are persisted in Redis via the excellent [Kredis](https://github.com/rails/kredis) gem, which must be set up and running in your project before you can use Polutan.
92
+ {% endhint %}
93
+
94
+ Polutan is based on [Active Entity](https://github.com/jasl/activeentity). It is similar to using [ActiveModel::Model](https://api.rubyonrails.org/classes/ActiveModel/Model.html), except that it has full support for [Attributes](https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute), including arrays and nested attributes. Polutan classes behave like ActiveModel classes, so you can inspect `valid?` and the `errors` accessor.
95
+
96
+ ```ruby
97
+ class ExampleModel < Possibility
98
+ attribute :name, :string
99
+ validates :name, presence: true
100
+ end
101
+
102
+ model = ExampleModel.new
103
+ model.valid? # false
104
+ model.errors # @errors=[#<ActiveModel::Error attribute=name, type=blank, options={}>]
105
+ ```
106
+
107
+ {% hint style="info" %}
108
+ Unlike an ActiveRecord model, Polutan instances can persist their attributes even if the attributes are currently invalid. This design allows you to resolve any errors present, even if it takes several distinct operations to do so.
109
+ {% endhint %}
110
+
111
+ {% hint style="success" %}
112
+ Once the state of your attributes is valid, you can pass the `attributes` from your Polutan model right into the constructor of a real ActiveRecord model. It should work perfectly.
113
+ {% endhint %}
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "pry"
data/SUMMARY.md ADDED
@@ -0,0 +1,5 @@
1
+ # Table of contents
2
+
3
+ * [Polutan](README.md)
4
+ * [Setup](setup.md)
5
+ * [Usage](usage.md)
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "polutan"
5
+ require "pry"
6
+
7
+ Pry.start
data/bin/loc ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ cloc --exclude-dir=node_modules,test --include-ext=rb,js .
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/standardize ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle exec magic_frozen_string_literal
4
+ bundle exec standardrb --fix
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Polutan
4
+ class Config
5
+ # Not implemented yet due to there being no configuration
6
+
7
+ # include Singleton
8
+ # attr_accessor :tomorrow
9
+
10
+ # def initialize
11
+ # @tomorrow = Infinity
12
+ # end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ class Possibility < ActiveEntity::Base
2
+ attr_accessor :id
3
+
4
+ def initialize(attributes={})
5
+ super
6
+ unless @id
7
+ @id = SecureRandom.uuid
8
+ save
9
+ end
10
+ end
11
+
12
+ def []=(attr_name, value)
13
+ super
14
+ save
15
+ end
16
+
17
+ def save
18
+ Kredis.json("#{self.class.name}:#{@id}").value = self.attributes.to_json
19
+ changes_applied
20
+ end
21
+
22
+ def self.find(id)
23
+ raise ArgumentError unless id
24
+ json = Kredis.json("#{name}:#{id}").value
25
+ raise ActiveRecord::RecordNotFound unless json
26
+ new json.merge(id: id)
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Polutan
4
+ VERSION = "1.0.0"
5
+ end
data/lib/polutan.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require "rails/engine"
4
+ # require "singleton"
5
+ # require "active_support/all"
6
+
7
+ require "active_entity/railtie"
8
+ require "polutan/version"
9
+ require "polutan/possibility"
10
+
11
+ module Polutan
12
+ # class Engine < Rails::Engine
13
+ # end
14
+
15
+ # def self.config
16
+ # Polutan::Config.instance
17
+ # end
18
+
19
+ # def self.configure
20
+ # yield config
21
+ # end
22
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: polutan
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nervive
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kredis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activeentity
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '6.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '6.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: magic_frozen_string_literal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.2.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-nav
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13.0'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 13.0.3
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '13.0'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 13.0.3
103
+ - !ruby/object:Gem::Dependency
104
+ name: standardrb
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '1.0'
117
+ description:
118
+ email:
119
+ - hello@nervive.studio
120
+ executables: []
121
+ extensions: []
122
+ extra_rdoc_files: []
123
+ files:
124
+ - Gemfile
125
+ - Gemfile.lock
126
+ - LICENSE.txt
127
+ - README.md
128
+ - Rakefile
129
+ - SUMMARY.md
130
+ - bin/console
131
+ - bin/loc
132
+ - bin/setup
133
+ - bin/standardize
134
+ - lib/polutan.rb
135
+ - lib/polutan/config.rb
136
+ - lib/polutan/possibility.rb
137
+ - lib/polutan/version.rb
138
+ homepage: https://polutan.nervive.studio/
139
+ licenses:
140
+ - MIT
141
+ metadata:
142
+ source_code_uri: https://github.com/nervive/polutan
143
+ documentation_uri: https://polutan.nervive.studio/
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubygems_version: 3.1.6
160
+ signing_key:
161
+ specification_version: 4
162
+ summary: A Redis-backed virtual ActiveModel, full of possibilities.
163
+ test_files: []