gourami 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.vscode/settings.json +5 -0
- data/gourami.gemspec +1 -0
- data/lib/gourami/coercer.rb +6 -1
- data/lib/gourami/extensions/resources.rb +17 -7
- data/lib/gourami/form.rb +30 -0
- data/lib/gourami/plugins/sanitize.rb +37 -0
- data/lib/gourami/plugins.rb +6 -0
- data/lib/gourami/version.rb +1 -1
- data/lib/gourami.rb +1 -0
- metadata +20 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79b225001fdeb796c9a6224beb9c7c792f37ae0ae7f48be33a2a4ca27f938979
|
|
4
|
+
data.tar.gz: 9fa37364de4f3c646f51f864798029564629a012e16b85877822629d579650a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b421bf22515e7380abf2a247e74e057ba26eed52d29dc7b2a8f2a13a0f2f72608f0ae6a2c1b0ca5ea4138a4b756b73cb8d9cf234f0bb416237c63c866b06f59
|
|
7
|
+
data.tar.gz: f7dd343730a9503d267f3c39ebb7b769eb62347283a69e5848f0a8e7766b1dcb2da5707eb0b71251eb0f39bdddce47d0fcee212493e811a06618bdbc20be2618
|
data/gourami.gemspec
CHANGED
|
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
|
|
24
24
|
spec.add_development_dependency "activesupport", ">= 5.1.7"
|
|
25
25
|
spec.add_development_dependency "filewatcher", "~> 1.1.0"
|
|
26
|
+
spec.add_development_dependency "loofah", ">= 2.24.0"
|
|
26
27
|
spec.add_development_dependency "minitest", "~> 5.0"
|
|
27
28
|
spec.add_development_dependency "pry", "~>0.10"
|
|
28
29
|
spec.add_development_dependency "rake", "~> 10.0"
|
data/lib/gourami/coercer.rb
CHANGED
|
@@ -11,7 +11,12 @@ module Gourami
|
|
|
11
11
|
# @return [*]
|
|
12
12
|
def setter_filter(attribute_name, value, options)
|
|
13
13
|
type = options[:type]
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
if type
|
|
16
|
+
raise ":coerce_#{type} does not exist. Did you forget to add a plugin for :coerce_#{type}?" unless respond_to?(:"coerce_#{type}")
|
|
17
|
+
|
|
18
|
+
value = send(:"coerce_#{type}", value, options)
|
|
19
|
+
end
|
|
15
20
|
|
|
16
21
|
super(attribute_name, value, options)
|
|
17
22
|
end
|
|
@@ -72,7 +72,7 @@ module Gourami
|
|
|
72
72
|
# validate_presence(:trim_end_time) # validates `attributes[:social_broadcasts]["facebook_page-41"][:trim_end_time]`
|
|
73
73
|
# end
|
|
74
74
|
# end
|
|
75
|
-
def with_resource(resource_namespace, resource_uid, offset: nil, &_block)
|
|
75
|
+
def with_resource(resource_namespace, resource_uid = nil, offset: nil, &_block)
|
|
76
76
|
@resource_namespace = resource_namespace
|
|
77
77
|
@resource_uid = resource_uid
|
|
78
78
|
@offset = offset
|
|
@@ -86,8 +86,10 @@ module Gourami
|
|
|
86
86
|
# If a resource namespace is active (within with_resource block), find the resource using the namespace and uid.
|
|
87
87
|
# Otherwise, return the form object.
|
|
88
88
|
def current_resource
|
|
89
|
-
if @resource_namespace
|
|
89
|
+
if @resource_namespace && @resource_uid
|
|
90
90
|
send(@resource_namespace)[@resource_uid]
|
|
91
|
+
elsif @resource_namespace
|
|
92
|
+
send(@resource_namespace)
|
|
91
93
|
else
|
|
92
94
|
super
|
|
93
95
|
end
|
|
@@ -156,13 +158,21 @@ module Gourami
|
|
|
156
158
|
end
|
|
157
159
|
|
|
158
160
|
# TODO: YARD
|
|
159
|
-
def resource_has_errors?(resource_namespace, resource_uid)
|
|
160
|
-
resource_errors[resource_namespace][resource_uid
|
|
161
|
+
def resource_has_errors?(resource_namespace, resource_uid = nil)
|
|
162
|
+
resource_errors[resource_namespace][resource_uid&.to_s].values.map(&:flatten).any?
|
|
161
163
|
end
|
|
162
164
|
|
|
163
165
|
# TODO: YARD
|
|
164
|
-
def resource_attribute_has_errors?(resource_namespace,
|
|
165
|
-
|
|
166
|
+
def resource_attribute_has_errors?(resource_namespace, resource_uid_or_attribute_name, attribute_name = nil)
|
|
167
|
+
if attribute_name.nil?
|
|
168
|
+
# 2 arguments: resource_namespace, attribute_name
|
|
169
|
+
attribute_name = resource_uid_or_attribute_name
|
|
170
|
+
resource_uid = nil
|
|
171
|
+
else
|
|
172
|
+
# 3 arguments: resource_namespace, resource_uid, attribute_name
|
|
173
|
+
resource_uid = resource_uid_or_attribute_name
|
|
174
|
+
end
|
|
175
|
+
resource_errors[resource_namespace][resource_uid&.to_s][attribute_name].any?
|
|
166
176
|
end
|
|
167
177
|
|
|
168
178
|
# Append an error to the given attribute for a resource.
|
|
@@ -174,7 +184,7 @@ module Gourami
|
|
|
174
184
|
# @param error [Symbol, String]
|
|
175
185
|
# The error identifier.
|
|
176
186
|
def append_resource_error(resource_namespace, resource_uid, attribute_name, error)
|
|
177
|
-
resource_errors[resource_namespace][resource_uid
|
|
187
|
+
resource_errors[resource_namespace][resource_uid&.to_s][attribute_name] << error
|
|
178
188
|
end
|
|
179
189
|
|
|
180
190
|
# Determine if current form instance is valid by running the validations
|
data/lib/gourami/form.rb
CHANGED
|
@@ -88,5 +88,35 @@ module Gourami
|
|
|
88
88
|
include Gourami::Validations
|
|
89
89
|
include Gourami::Coercer
|
|
90
90
|
|
|
91
|
+
# Load and apply a plugin.
|
|
92
|
+
# Inspired by the plugin system from the Sequel gem. https://janko.io/the-plugin-system-of-sequel-and-roda/
|
|
93
|
+
#
|
|
94
|
+
# @param name [Symbol, Module] a name to look up under Gourami::Plugins
|
|
95
|
+
# (e.g. :sanitize loads gourami/plugins/sanitize and resolves
|
|
96
|
+
# Gourami::Plugins::Sanitize), or a Module to apply directly.
|
|
97
|
+
def self.plugin(name, *args, &block)
|
|
98
|
+
plugin_module = load_plugin(name)
|
|
99
|
+
|
|
100
|
+
plugin_module.apply(self, *args, &block) if plugin_module.respond_to?(:apply)
|
|
101
|
+
|
|
102
|
+
extend(plugin_module::ClassMethods) if plugin_module.const_defined?(:ClassMethods)
|
|
103
|
+
include(plugin_module::InstanceMethods) if plugin_module.const_defined?(:InstanceMethods)
|
|
104
|
+
|
|
105
|
+
plugin_module.configure(self, *args, &block) if plugin_module.respond_to?(:configure)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def self.load_plugin(name)
|
|
109
|
+
return name if name.is_a?(Module)
|
|
110
|
+
|
|
111
|
+
const_name = name.to_s.split("_").map { |part| part[0].upcase + part[1..-1] }.join
|
|
112
|
+
|
|
113
|
+
unless Gourami::Plugins.const_defined?(const_name)
|
|
114
|
+
require "gourami/plugins/#{name}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
Gourami::Plugins.const_get(const_name)
|
|
118
|
+
end
|
|
119
|
+
private_class_method :load_plugin
|
|
120
|
+
|
|
91
121
|
end
|
|
92
122
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Optional plugin adding a :sanitized_string attribute type that strips dangerous HTML
|
|
2
|
+
# using loofah. Not loaded by default - opt in with `plugin :sanitize`, and add
|
|
3
|
+
# "loofah" to your own application's Gemfile/gemspec.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# class MyForm < Gourami::Form
|
|
7
|
+
# plugin :sanitize
|
|
8
|
+
#
|
|
9
|
+
# attribute :bio, :type => :sanitized_string
|
|
10
|
+
# end
|
|
11
|
+
module Gourami
|
|
12
|
+
module Plugins
|
|
13
|
+
module Sanitize
|
|
14
|
+
# Runs on every `plugin :sanitize` call; require is idempotent so this is safe to repeat.
|
|
15
|
+
def self.apply(_model, *)
|
|
16
|
+
require "loofah"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module InstanceMethods
|
|
20
|
+
# @param value [Object]
|
|
21
|
+
# @param options [Hash] forwarded to #coerce_string
|
|
22
|
+
# @return [String, nil]
|
|
23
|
+
def coerce_sanitized_string(value, options = {})
|
|
24
|
+
value = coerce_string(value, options)
|
|
25
|
+
return value if value.nil?
|
|
26
|
+
|
|
27
|
+
# Unescape first so entity-encoded tags (e.g. "<script>") are
|
|
28
|
+
# recognized as real HTML by Loofah instead of passing through as text.
|
|
29
|
+
unescaped_content = CGI.unescapeHTML(value)
|
|
30
|
+
sanitized_content = Loofah.html4_fragment(unescaped_content).scrub!(:prune).to_s
|
|
31
|
+
# Unescape again since loofah would turn a & back into &
|
|
32
|
+
CGI.unescapeHTML(sanitized_content).strip
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/gourami/version.rb
CHANGED
data/lib/gourami.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gourami
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- TSMMark
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-08-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -38,6 +38,20 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 1.1.0
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: loofah
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 2.24.0
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 2.24.0
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: minitest
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -91,6 +105,7 @@ files:
|
|
|
91
105
|
- ".github/workflows/ci.yml"
|
|
92
106
|
- ".gitignore"
|
|
93
107
|
- ".ruby-version"
|
|
108
|
+
- ".vscode/settings.json"
|
|
94
109
|
- CODE_OF_CONDUCT.md
|
|
95
110
|
- Gemfile
|
|
96
111
|
- LICENSE.txt
|
|
@@ -110,6 +125,8 @@ files:
|
|
|
110
125
|
- lib/gourami/form.rb
|
|
111
126
|
- lib/gourami/formatting_constants.rb
|
|
112
127
|
- lib/gourami/not_watching_changes_error.rb
|
|
128
|
+
- lib/gourami/plugins.rb
|
|
129
|
+
- lib/gourami/plugins/sanitize.rb
|
|
113
130
|
- lib/gourami/required_attribute_error.rb
|
|
114
131
|
- lib/gourami/validation_error.rb
|
|
115
132
|
- lib/gourami/validations.rb
|
|
@@ -134,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
134
151
|
- !ruby/object:Gem::Version
|
|
135
152
|
version: '0'
|
|
136
153
|
requirements: []
|
|
137
|
-
rubygems_version: 3.4.
|
|
154
|
+
rubygems_version: 3.4.21
|
|
138
155
|
signing_key:
|
|
139
156
|
specification_version: 4
|
|
140
157
|
summary: Keep your Routes, Controllers and Models thin.
|