tuning 0.3.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|