tuning 0.3.3 → 1.0.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/MIT-LICENSE +1 -1
- data/README.md +80 -17
- data/Rakefile +3 -0
- data/lib/tuning.rb +7 -2
- data/lib/tuning/extensions/action_controller/base.rb +45 -0
- data/lib/tuning/extensions/action_mailer/base.rb +22 -0
- data/lib/tuning/extensions/action_view/base.rb +31 -0
- data/lib/tuning/extensions/active_record/base.rb +25 -0
- data/lib/tuning/locales/en.yml +12 -0
- data/lib/tuning/locales/es.yml +12 -0
- data/lib/tuning/railtie.rb +17 -3
- data/lib/tuning/validations/complexity.rb +22 -0
- data/lib/tuning/validations/count.rb +42 -0
- data/lib/tuning/validations/time.rb +38 -0
- data/lib/tuning/version.rb +1 -1
- data/test/controllers_test.rb +21 -0
- data/test/dummy/Rakefile +1 -2
- data/test/dummy/app/assets/javascripts/application.js +2 -2
- data/test/dummy/app/assets/stylesheets/application.css +6 -4
- data/test/dummy/app/mailers/user_mailer.rb +7 -0
- data/test/dummy/app/models/shop.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +0 -12
- data/test/dummy/app/views/layouts/market.html.erb +3 -0
- data/test/dummy/app/views/user_mailer/invite.text.erb +7 -0
- data/test/dummy/bin/bundle +0 -0
- data/test/dummy/bin/rails +1 -1
- data/test/dummy/bin/rake +0 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +1 -1
- data/test/dummy/config/application.rb +3 -1
- data/test/dummy/config/boot.rb +1 -1
- data/test/dummy/config/database.yml +4 -22
- data/test/dummy/config/database.yml.travis +12 -0
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/development.rb +14 -2
- data/test/dummy/config/environments/production.rb +20 -25
- data/test/dummy/config/environments/test.rb +8 -10
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/mime_types.rb +1 -2
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/locales/en.yml +22 -9
- data/test/dummy/config/routes.rb +2 -7
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/migrate/20161020200126_create_shops.rb +9 -0
- data/test/dummy/db/migrate/20161022144717_create_records.rb +6 -0
- data/test/dummy/db/schema.rb +15 -1
- data/test/dummy/log/test.log +70 -0
- data/test/dummy/public/404.html +20 -11
- data/test/dummy/public/422.html +20 -11
- data/test/dummy/public/500.html +19 -10
- data/test/helpers_test.rb +39 -0
- data/test/mailers_test.rb +10 -0
- data/test/records_test.rb +16 -0
- data/test/test_helper.rb +5 -18
- data/test/validations_test.rb +192 -0
- metadata +66 -47
- data/lib/tuning/action_controller/base.rb +0 -54
- data/lib/tuning/action_view/base.rb +0 -16
- data/test/active_trail_test.rb +0 -33
- data/test/content_tag_if_test.rb +0 -17
- data/test/dummy/README.rdoc +0 -28
- data/test/dummy/app/controllers/status_controller.rb +0 -27
- data/test/dummy/config/initializers/secret_token.rb +0 -13
- data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/status_test.rb +0 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 343b848737c55c9904274280fa22d39825774cd6
|
4
|
+
data.tar.gz: d958a82c6f8109cc0349978d59bbc23fda0ce85c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49d74ede892d4044c00902cc3ddd33cb405fa79b00406e3ad975a3b2b1eb0b72337ad13fad9899580da53b4e9983b25562b8be877abc49bbded7c8fb4a651f1a
|
7
|
+
data.tar.gz: 3641e84db0a2bc40ab09def6907be2b3a60e6efccd3c2ede3de92f620583f1eaad6655efec327171623f5767c81867807bc035e64a23cf48f95556335130f0dc
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -21,45 +21,108 @@ $ bundle
|
|
21
21
|
|
22
22
|
## Controllers
|
23
23
|
|
24
|
-
|
24
|
+
New callbacks before, after, around render are available:
|
25
25
|
```ruby
|
26
|
-
|
27
|
-
```
|
26
|
+
class ProductsController < ApplicationController
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
before_action :set_product
|
29
|
+
before_render :prepare_product
|
30
|
+
|
31
|
+
def edit
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def set_product
|
37
|
+
@product = Product.find(params[:id])
|
38
|
+
end
|
39
|
+
|
40
|
+
def prepare_product
|
41
|
+
@product.build_picture
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
32
45
|
```
|
33
46
|
|
34
|
-
|
35
|
-
|
36
|
-
|
47
|
+
## Mailers
|
48
|
+
|
49
|
+
Text email templates will normalize spaces and new lines like html:
|
50
|
+
```erb
|
51
|
+
<% if @order.confirmed? %>
|
52
|
+
Your order has been confirmed.
|
53
|
+
|
54
|
+
Will be delivered right the way.
|
55
|
+
<% end %>
|
37
56
|
```
|
38
57
|
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
forbidden
|
58
|
+
Will produce:
|
42
59
|
```
|
60
|
+
Your order has been confirmed.
|
43
61
|
|
44
|
-
|
45
|
-
```ruby
|
46
|
-
unprocessable_entity
|
62
|
+
Will be delivered right the way.
|
47
63
|
```
|
48
64
|
|
49
65
|
## Views
|
50
66
|
|
51
|
-
|
67
|
+
New content_tag_if method to wrap content into some tag if certain condition it's true:
|
52
68
|
```erb
|
53
69
|
<%= content_tag_if request.path == home_path, :h1 do %>
|
54
70
|
<%= link_to 'Home', home_path, id: 'logo' %>
|
55
71
|
<% end %>
|
56
72
|
```
|
57
73
|
|
58
|
-
|
74
|
+
New active_trail? method to check if some path is on active trail:
|
59
75
|
```erb
|
60
76
|
<li class="<%= 'active' if active_trail? some_path %>"></li>
|
61
77
|
```
|
62
78
|
|
79
|
+
New extending method to extend layouts:
|
80
|
+
```erb
|
81
|
+
<%= extending :application do %>
|
82
|
+
<p>content</p>
|
83
|
+
<% end %>
|
84
|
+
```
|
85
|
+
|
86
|
+
## Records
|
87
|
+
|
88
|
+
Empty strings will be nilify in the database to avoid sql errors or complex queries:
|
89
|
+
```ruby
|
90
|
+
shop = Shop.new(name: '')
|
91
|
+
shop.save
|
92
|
+
shop.name # Will be nil
|
93
|
+
```
|
94
|
+
|
95
|
+
New method validate is available to allow a more expressive syntax:
|
96
|
+
```ruby
|
97
|
+
record.validate # Same as valid?
|
98
|
+
```
|
99
|
+
|
100
|
+
## Validations
|
101
|
+
|
102
|
+
Complexity validator to avoid weak passwords:
|
103
|
+
```ruby
|
104
|
+
class User < ActiveRecord::Base
|
105
|
+
validates_complexity_of :password
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
Count validator to express count messages instead of length messages:
|
110
|
+
```ruby
|
111
|
+
class Product < ActiveRecord::Base
|
112
|
+
validates_count_of :pictures, minimum: 1, maximum: 4 # Or in/within: 1..4
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
Time validator to validate Date/Time values:
|
117
|
+
```ruby
|
118
|
+
class Schedule < ActiveRecord::Base
|
119
|
+
validates_time_of :opens_at
|
120
|
+
validates_time_of :closes_at, after: :opens_at # Or before, after_or_equal_to or before_or_equal_to
|
121
|
+
end
|
122
|
+
```
|
123
|
+
|
124
|
+
NOTE: Take a look at lib/tuning/locales to know the i18n keys.
|
125
|
+
|
63
126
|
## Credits
|
64
127
|
|
65
128
|
This gem is maintained and funded by [mmontossi](https://github.com/mmontossi).
|
data/Rakefile
CHANGED
data/lib/tuning.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
-
require 'tuning/action_controller/base'
|
2
|
-
require 'tuning/
|
1
|
+
require 'tuning/extensions/action_controller/base'
|
2
|
+
require 'tuning/extensions/action_mailer/base'
|
3
|
+
require 'tuning/extensions/action_view/base'
|
4
|
+
require 'tuning/extensions/active_record/base'
|
5
|
+
require 'tuning/validations/complexity'
|
6
|
+
require 'tuning/validations/count'
|
7
|
+
require 'tuning/validations/time'
|
3
8
|
require 'tuning/railtie'
|
4
9
|
|
5
10
|
module Tuning
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Tuning
|
2
|
+
module Extensions
|
3
|
+
module ActionController
|
4
|
+
module Base
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
define_callbacks :render
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(*args)
|
12
|
+
run_callbacks(:render) do
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
|
19
|
+
%i(before after around).each do |callback|
|
20
|
+
define_method "#{callback}_render" do |*names, &block|
|
21
|
+
_insert_callbacks(args, block) do |name, options|
|
22
|
+
set_callback :render, callback, name, options
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
define_method "prepend_#{callback}_render" do |*names, &block|
|
27
|
+
_insert_callbacks(args, block) do |name, options|
|
28
|
+
set_callback :render, callback, name, options.merge(prepend: true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
define_method "skip_#{callback}_render" do |*names|
|
33
|
+
_insert_callbacks(args) do |name, options|
|
34
|
+
skip_callback :render, callback, name, options
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
alias_method :"append_#{callback}_render", :"#{callback}_render"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Tuning
|
2
|
+
module Extensions
|
3
|
+
module ActionMailer
|
4
|
+
module Base
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
after_action :normalize_text_body
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def normalize_text_body
|
14
|
+
if mail.content_type.starts_with?('text/plain')
|
15
|
+
mail.body = mail.body.to_s.gsub(/\n{3,}/, "\n\n").gsub(/\n +/, "\n").gsub(/^ +/, '')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Tuning
|
2
|
+
module Extensions
|
3
|
+
module ActionView
|
4
|
+
module Base
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def active_trail?(path)
|
8
|
+
(path == '/' && request.path == path) || request.path.start_with?(path)
|
9
|
+
end
|
10
|
+
|
11
|
+
def content_tag_if(condition, name, options={}, &block)
|
12
|
+
if condition
|
13
|
+
content_tag(name, options, &block)
|
14
|
+
else
|
15
|
+
capture(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def extending(layout, &block)
|
20
|
+
if block_given?
|
21
|
+
old_layout = @view_flow.get(:layout)
|
22
|
+
new_layout = (capture(&block) || '')
|
23
|
+
old_layout.replace(new_layout)
|
24
|
+
end
|
25
|
+
render file: "layouts/#{layout}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Tuning
|
2
|
+
module Extensions
|
3
|
+
module ActiveRecord
|
4
|
+
module Base
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_save :nilify_blank_attributes
|
9
|
+
alias_method :validate, :valid?
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def nilify_blank_attributes
|
15
|
+
attributes.each do |column, value|
|
16
|
+
if value.is_a? String and value.blank?
|
17
|
+
self[column] = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
en:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
too_easy: "is too easy"
|
5
|
+
too_many: "must have maximum %{count}"
|
6
|
+
too_few: "must have minimum %{count}"
|
7
|
+
wrong_count: "must have %{count}"
|
8
|
+
not_a_time: "is not a time"
|
9
|
+
after: "must be after %{time}"
|
10
|
+
after_or_equal_to: "must be after or equal to %{time}"
|
11
|
+
before: "must be before %{time}"
|
12
|
+
before_or_equal_to: "must be before or equal to %{time}"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
es:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
too_easy: "es muy fácil"
|
5
|
+
too_many: "debe tener máximo %{count}"
|
6
|
+
too_few: "debe tener mínimo %{count}"
|
7
|
+
wrong_count: "debe tener %{count}"
|
8
|
+
not_a_time: "no es un tiempo"
|
9
|
+
after: "debe ser posterior a %{time}"
|
10
|
+
after_or_equal_to: "tiene que ser posterior o igual a %{time}"
|
11
|
+
before: "debe ser anterior a %{time}"
|
12
|
+
before_or_equal_to: "tiene que ser anterior o igual a %{time}"
|
data/lib/tuning/railtie.rb
CHANGED
@@ -1,9 +1,23 @@
|
|
1
1
|
module Tuning
|
2
2
|
class Railtie < Rails::Railtie
|
3
3
|
|
4
|
-
initializer
|
5
|
-
::ActionController::Base.
|
6
|
-
|
4
|
+
initializer :tuning do
|
5
|
+
::ActionController::Base.include(
|
6
|
+
Tuning::Extensions::ActionController::Base
|
7
|
+
)
|
8
|
+
::ActionMailer::Base.include(
|
9
|
+
Tuning::Extensions::ActionMailer::Base
|
10
|
+
)
|
11
|
+
::ActionView::Base.include(
|
12
|
+
Tuning::Extensions::ActionView::Base
|
13
|
+
)
|
14
|
+
::ActiveRecord::Base.include(
|
15
|
+
Tuning::Extensions::ActiveRecord::Base,
|
16
|
+
Tuning::Validations
|
17
|
+
)
|
18
|
+
::ActiveModel::Model.include(
|
19
|
+
Tuning::Validations
|
20
|
+
)
|
7
21
|
end
|
8
22
|
|
9
23
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Tuning
|
2
|
+
module Validations
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class ComplexityValidator < ActiveModel::EachValidator
|
6
|
+
|
7
|
+
def validate_each(record, attribute, value)
|
8
|
+
if value !~ /\A(?=.*[a-z])(?=.*[A-Z])(?=.*[\d])(?=.*[\W\_]).{8,}*\z/
|
9
|
+
record.errors.add attribute, :too_easy
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def validates_complexity_of(*attr_names)
|
17
|
+
validates_with ComplexityValidator, _merge_attributes(attr_names)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Tuning
|
2
|
+
module Validations
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class CountValidator < ActiveModel::EachValidator
|
6
|
+
MESSAGES = { is: :wrong_count, minimum: :too_few, maximum: :too_many }
|
7
|
+
CHECKS = { is: :==, minimum: :>=, maximum: :<= }
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
if range = (options[:in] || options[:within])
|
11
|
+
options[:minimum] = range.min
|
12
|
+
options[:maximum] = range.max
|
13
|
+
end
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_each(record, attribute, value)
|
18
|
+
if value.respond_to?(:size)
|
19
|
+
count = value.size
|
20
|
+
CHECKS.each do |name, operator|
|
21
|
+
if options.has_key?(name)
|
22
|
+
other = options[name]
|
23
|
+
unless count.send(operator, other)
|
24
|
+
record.errors.add attribute, MESSAGES[name], count: other
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
record.errors.add attribute, :uncountable
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
module ClassMethods
|
35
|
+
|
36
|
+
def validates_count_of(*attr_names)
|
37
|
+
validates_with CountValidator, _merge_attributes(attr_names)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Tuning
|
2
|
+
module Validations
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class TimeValidator < ActiveModel::EachValidator
|
6
|
+
CHECKS = { before: :<, before_or_equal_to: :<=, after: :>, after_or_equal_to: :>= }
|
7
|
+
|
8
|
+
def validate_each(record, attribute, value)
|
9
|
+
if [Date, Time].any? { |klass| value.kind_of?(klass) }
|
10
|
+
CHECKS.each do |name, operator|
|
11
|
+
if options.has_key?(name)
|
12
|
+
other = options[name]
|
13
|
+
case other
|
14
|
+
when Symbol
|
15
|
+
other = record.send(other)
|
16
|
+
when Proc
|
17
|
+
other = other.call(record)
|
18
|
+
end
|
19
|
+
unless value.send(operator, other)
|
20
|
+
record.errors.add attribute, name, time: I18n.l(other)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
else
|
25
|
+
record.errors.add attribute, :not_a_time
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
module ClassMethods
|
31
|
+
|
32
|
+
def validates_time_of(*attr_names)
|
33
|
+
validates_with TimeValidator, _merge_attributes(attr_names)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|