rails_stuff 0.6.0.rc1 → 0.6.0.rc2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 56cd33390b1d0c5cce251aba39698ef115de3c6c
4
- data.tar.gz: 8e7032d8717fae0d1fa44c5f6ea308a150a2e73f
3
+ metadata.gz: 8d4bbc5a4f7134f1f2d424f3657a959fadc156f7
4
+ data.tar.gz: 02c9c3a91387da5b74b651db8170485e2e3f32b9
5
5
  SHA512:
6
- metadata.gz: 9abf798f564088d2bb174e955efdf0cce9b47528b8f0dac7095516a35fcd11752772cd3d691266235698fd5281622db8ce9f5f9d32a3d66a75c8efde2c5da87c
7
- data.tar.gz: 3dbbc5a6052014726fba018811d5615d9e9527e913fb14a492d615527f4bbe6bb5312815d55549e613e38c6103728447e7b558c8f1bbf630c18d65eb897bfc13
6
+ metadata.gz: 546ed27d8f2dfae81802312f33ffc53783e428eab45355334460e9efeb7e75e55b6a59c492290ee1519f535c747ac965647cb118c5c093e26f5b3f9f4eb80e42
7
+ data.tar.gz: 809b2cff8da75c31810e4f1d5bd78fa4e344d1931d898d7627bccf51d5d48a0ae82cdf7508390138e87c15e5b5b0978c55ad56025b10fccfdd4997c55e1bbcb9
@@ -4,29 +4,53 @@ AllCops:
4
4
  - tmp/**/*
5
5
  Rails: {Enabled: true}
6
6
 
7
- Style/Alias: {Enabled: false}
8
- Style/AlignParameters:
7
+ Layout/AlignParameters:
9
8
  # Disable, till rubocop supports combination of styles.
10
9
  # Use one of this styles where appropriate, keep it clean, compact and readable.
11
10
  Enabled: false
12
11
  # EnforcedStyle:
13
12
  # - with_first_parameter
14
13
  # - with_fixed_indentation
15
- Style/ClosingParenthesisIndentation: {Enabled: false}
14
+
15
+ # Breaks
16
+ #
17
+ # I18n.t(key,
18
+ # param: val,
19
+ # # ...
20
+ # )
21
+ Layout/ClosingParenthesisIndentation: {Enabled: false}
22
+ Layout/DotPosition: {EnforcedStyle: trailing}
23
+ # Same as Layout/ClosingParenthesisIndentation
24
+ Layout/MultilineMethodCallBraceLayout: {Enabled: false}
25
+ Layout/MultilineMethodCallIndentation: {EnforcedStyle: indented}
26
+ Layout/MultilineOperationIndentation: {EnforcedStyle: indented}
27
+ Layout/SpaceInsideHashLiteralBraces: {EnforcedStyle: no_space}
28
+
29
+ # Offences named scopes and `expect {}.to change {}`.
30
+ Lint/AmbiguousBlockAssociation: {Enabled: false}
31
+
32
+ # We use it in describe messages.
33
+ Lint/InterpolationCheck:
34
+ Exclude:
35
+ - spec/**/*
36
+
37
+ Naming/PredicateName: {Enabled: false}
38
+ Naming/VariableNumber: {EnforcedStyle: snake_case}
39
+
40
+ Style/Alias: {Enabled: false}
16
41
  Style/Documentation: {Enabled: false}
17
- Style/DotPosition: {EnforcedStyle: trailing}
18
42
  Style/IfUnlessModifier: {Enabled: false}
43
+ Style/GuardClause: {Enabled: false}
19
44
  Style/Lambda: {Enabled: false}
20
45
  Style/ModuleFunction: {Enabled: false}
21
- Style/MultilineMethodCallIndentation: {EnforcedStyle: indented}
22
- Style/MultilineOperationIndentation: {EnforcedStyle: indented}
23
46
  Style/NestedParenthesizedCalls: {Enabled: false}
24
- Style/PredicateName: {Enabled: false}
25
47
  Style/SignalException: {EnforcedStyle: only_raise}
26
- Style/SpaceInsideHashLiteralBraces: {EnforcedStyle: no_space}
27
48
  Style/TrailingCommaInArguments: {Enabled: false}
28
49
  Style/TrailingCommaInLiteral: {EnforcedStyleForMultiline: comma}
29
50
 
30
51
  Metrics/AbcSize: {Max: 21}
52
+ # Other metrics are just enough.
53
+ # This one offences all specs, routes and some initializers.
54
+ Metrics/BlockLength: {Enabled: false}
31
55
  Metrics/LineLength: {Max: 100}
32
56
  Metrics/MethodLength: {Max: 30}
@@ -4,7 +4,8 @@ rvm:
4
4
  - 2.2.3
5
5
  gemfile:
6
6
  - gemfiles/rails_4.gemfile
7
- - gemfiles/rails_5.gemfile
7
+ - gemfiles/rails_5_0.gemfile
8
+ - gemfiles/rails_5_1.gemfile
8
9
  services:
9
10
  - redis
10
11
  notifications:
data/Appraisals CHANGED
@@ -4,9 +4,16 @@ appraise 'rails-4' do
4
4
  end
5
5
  end
6
6
 
7
- appraise 'rails-5' do
7
+ appraise 'rails-5_0' do
8
8
  group :development do
9
- gem 'rails', '~> 5.0'
9
+ gem 'rails', '~> 5.0.0'
10
+ gem 'rails-controller-testing', '~> 0.1.1'
11
+ end
12
+ end
13
+
14
+ appraise 'rails-5_1' do
15
+ group :development do
16
+ gem 'rails', '~> 5.1'
10
17
  gem 'rails-controller-testing', '~> 0.1.1'
11
18
  end
12
19
  end
@@ -1,5 +1,22 @@
1
1
  ## Unreleased
2
2
 
3
+ ### Controllers
4
+
5
+ - `resource_params` returns permited hash when resource key is not present in `params`.
6
+ - `use_resource_class_for_invalid_type` option for STI helpers,
7
+ and `RailsStuff::ResourcesController::StiHelpers::InvalidType` error instead of
8
+ `ActiveRecord::NotFound` for invalid type.
9
+
10
+ ### Models
11
+
12
+ - `TransformAttrs` in favour of `NullifyBlankAttrs` (deprecated).
13
+
14
+ ### Misc
15
+
16
+ - Parse BigDecimals with ParamsParser.
17
+ - ParamsParser parses empty strings to `nil` (except `parse_string`).
18
+
19
+
3
20
  ## 0.6.0.rc1
4
21
 
5
22
  ### Controllers
data/Gemfile CHANGED
@@ -2,26 +2,26 @@ source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
4
  group :development do
5
- gem 'rails'
6
5
  gem 'appraisal', '~> 2.1.0'
6
+ gem 'rails'
7
7
 
8
- gem 'sdoc', '~> 0.4.1'
9
8
  gem 'pry', '~> 0.10.1'
10
9
  gem 'pry-byebug', '~> 3.2.0'
10
+ gem 'sdoc', '~> 0.4.1'
11
11
 
12
- gem 'sqlite3', '~> 1.3.10'
13
- gem 'database_cleaner', '~> 1.5.0'
14
- gem 'pooled_redis', '~> 0.2.1'
15
12
  gem 'activemodel_translation', '~> 0.1.0'
13
+ gem 'database_cleaner', '~> 1.5.0'
16
14
  gem 'has_scope', '~> 0.7.0'
17
- gem 'responders', '~> 2.1.0'
18
- gem 'kaminari', '~> 0.16.3'
19
15
  gem 'hashie', '~> 3.4.0'
16
+ gem 'kaminari', '~> 0.16.3'
17
+ gem 'pooled_redis', '~> 0.2.1'
18
+ gem 'responders', '~> 2.1'
19
+ gem 'sqlite3', '~> 1.3.10'
20
20
 
21
- gem 'rspec-rails', '~> 3.5.2'
22
21
  gem 'rspec-its', '~> 1.2.0'
22
+ gem 'rspec-rails', '~> 3.5'
23
23
 
24
- gem 'rubocop', '~> 0.37.2'
24
+ gem 'rubocop', '~> 0.51.0'
25
25
 
26
26
  gem 'coveralls', '~> 0.8.2', require: false
27
27
  end
data/README.md CHANGED
@@ -3,7 +3,15 @@
3
3
  [![Code Climate](https://codeclimate.com/github/printercu/rails_stuff/badges/gpa.svg)](https://codeclimate.com/github/printercu/rails_stuff)
4
4
  [![Build Status](https://travis-ci.org/printercu/rails_stuff.svg)](https://travis-ci.org/printercu/rails_stuff)
5
5
 
6
- Collection of useful modules for Rails.
6
+ Collection of useful modules for ruby projects to provide great DRY, TDD experience.
7
+ While some of them are Rails-specific, most will work in any environment
8
+ ignoring gem's name.
9
+
10
+ All modules are lazy loaded, so it's ok to require whole gem at once.
11
+ Some of them are activated by default for best experience,
12
+ but this can be configured or turned off (see [usage](#usage)).
13
+
14
+ Works with ruby 2.0+, Rails 4.2+, 5+.
7
15
 
8
16
  #### Controllers:
9
17
 
@@ -89,7 +97,6 @@ Or install it yourself as:
89
97
 
90
98
  ## Usage
91
99
 
92
- All modules are lazy loaded, so it's ok to require whole gem at once.
93
100
  There is railtie which will include some of modules into `ActiveRecord::Base`
94
101
  and `ActionController::Base` by default. You can disable this behavior in
95
102
  initializer:
@@ -105,8 +112,6 @@ RailsStuff.load_modules = %i(sort_scope statusable)
105
112
  You can override base classes for controller/model with `.base_controller=`,
106
113
  `.base_model=`.
107
114
 
108
- Works only with ruby 2.0+, tested with Rails 4.2.
109
-
110
115
  There can be lack of documentation in README. Please navigate to module and
111
116
  check docs & code (press `t` on github) if you miss something.
112
117
 
@@ -305,7 +310,7 @@ Project.internal or Project.big
305
310
  Have you missed type-casting outside of `ActiveRecord::Base`? Here is it:
306
311
 
307
312
  ```ruby
308
- ParamsParser.parse_int(params[:field]) # _float, _string, _boolean, _datetime
313
+ ParamsParser.parse_int(params[:field]) # _float, _decimal, _string, _boolean, _datetime
309
314
  ParamsParser.parse_int_array(params[:field_with_array])
310
315
  ParamsParser.parse_json(json_string)
311
316
 
@@ -13,10 +13,10 @@ group :development do
13
13
  gem "pooled_redis", "~> 0.2.1"
14
14
  gem "activemodel_translation", "~> 0.1.0"
15
15
  gem "has_scope", "~> 0.7.0"
16
- gem "responders", "~> 2.1.0"
16
+ gem "responders", "~> 2.1"
17
17
  gem "kaminari", "~> 0.16.3"
18
18
  gem "hashie", "~> 3.4.0"
19
- gem "rspec-rails", "~> 3.5.2"
19
+ gem "rspec-rails", "~> 3.5"
20
20
  gem "rspec-its", "~> 1.2.0"
21
21
  gem "rubocop", "~> 0.37.2"
22
22
  gem "coveralls", "~> 0.8.2", :require => false
@@ -3,7 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  group :development do
6
- gem "rails", "~> 5.0"
6
+ gem "rails", "~> 5.0.0"
7
7
  gem "appraisal", "~> 2.1.0"
8
8
  gem "sdoc", "~> 0.4.1"
9
9
  gem "pry", "~> 0.10.1"
@@ -13,10 +13,10 @@ group :development do
13
13
  gem "pooled_redis", "~> 0.2.1"
14
14
  gem "activemodel_translation", "~> 0.1.0"
15
15
  gem "has_scope", "~> 0.7.0"
16
- gem "responders", "~> 2.1.0"
16
+ gem "responders", "~> 2.1"
17
17
  gem "kaminari", "~> 0.16.3"
18
18
  gem "hashie", "~> 3.4.0"
19
- gem "rspec-rails", "~> 3.5.2"
19
+ gem "rspec-rails", "~> 3.5"
20
20
  gem "rspec-its", "~> 1.2.0"
21
21
  gem "rubocop", "~> 0.37.2"
22
22
  gem "coveralls", "~> 0.8.2", :require => false
@@ -0,0 +1,26 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ group :development do
6
+ gem "rails", "~> 5.1"
7
+ gem "appraisal", "~> 2.1.0"
8
+ gem "sdoc", "~> 0.4.1"
9
+ gem "pry", "~> 0.10.1"
10
+ gem "pry-byebug", "~> 3.2.0"
11
+ gem "sqlite3", "~> 1.3.10"
12
+ gem "database_cleaner", "~> 1.5.0"
13
+ gem "pooled_redis", "~> 0.2.1"
14
+ gem "activemodel_translation", "~> 0.1.0"
15
+ gem "has_scope", "~> 0.7.0"
16
+ gem "responders", "~> 2.1"
17
+ gem "kaminari", "~> 0.16.3"
18
+ gem "hashie", "~> 3.4.0"
19
+ gem "rspec-rails", "~> 3.5"
20
+ gem "rspec-its", "~> 1.2.0"
21
+ gem "rubocop", "~> 0.37.2"
22
+ gem "coveralls", "~> 0.8.2", :require => false
23
+ gem "rails-controller-testing", "~> 0.1.1"
24
+ end
25
+
26
+ gemspec :path => "../"
@@ -19,6 +19,7 @@ module RailsStuff
19
19
  autoload :SortScope
20
20
  autoload :Statusable
21
21
  autoload :TestHelpers, 'rails_stuff/test_helpers'
22
+ autoload :TransformAttrs
22
23
  autoload :TypesTracker
23
24
 
24
25
  module_function
@@ -30,6 +31,13 @@ module RailsStuff
30
31
  def rails4?
31
32
  rails_version::MAJOR == 4
32
33
  end
34
+
35
+ def deprecation_07
36
+ @deprecation ||= begin
37
+ require 'active_support/deprecation'
38
+ ActiveSupport::Deprecation.new('0.7', 'RailsStuff')
39
+ end
40
+ end
33
41
  end
34
42
 
35
43
  require 'rails_stuff/engine' if defined?(Rails::Engine)
@@ -7,6 +7,7 @@ module RailsStuff
7
7
  nullify_blank_attrs: :model,
8
8
  random_uniq_attr: :model,
9
9
  statusable: :model,
10
+ transform_attrs: :model,
10
11
  resources_controller: [
11
12
  -> { defined?(::Responders) && :controller },
12
13
  -> { ResourcesController.use_kaminari! if defined?(::Kaminari) },
@@ -59,5 +60,9 @@ module RailsStuff
59
60
  generators do
60
61
  require 'rails_stuff/generators/concern/concern_generator'
61
62
  end
63
+
64
+ config.action_dispatch.rescue_responses.merge!(
65
+ 'RailsStuff::ResourcesController::StiHelpers::InvalidType' => :unprocessable_entity,
66
+ )
62
67
  end
63
68
  end
@@ -11,13 +11,16 @@ module RailsStuff
11
11
  notice: 'alert-info',
12
12
  }.stringify_keys.freeze
13
13
 
14
+ CROSS = '×'.html_safe.freeze # rubocop:disable Rails/OutputSafety
15
+
14
16
  def flash_messages
15
- flash.map do |type, message|
17
+ messages = flash.map do |type, message|
16
18
  content_tag :div, class: [:alert, BOOTSTRAP_FLASH_TYPE[type] || type] do
17
- content_tag(:button, '×'.html_safe, class: :close, data: {dismiss: :alert}) +
19
+ content_tag(:button, cross, class: :close, data: {dismiss: :alert}) +
18
20
  simple_format(message)
19
21
  end
20
- end.join.html_safe
22
+ end
23
+ safe_join(messages)
21
24
  end
22
25
 
23
26
  ICONS = {
@@ -8,6 +8,7 @@ module RailsStuff
8
8
  # # ...
9
9
  module NullifyBlankAttrs
10
10
  def nullify_blank_attrs(*attrs)
11
+ RailsStuff.deprecation_07.warn('Use transform_attrs *attrs, with: :nullify')
11
12
  nullify_blank_attrs_methods.class_eval do
12
13
  attrs.each do |attr|
13
14
  define_method("#{attr}=") { |val| super(val.presence) }
@@ -44,16 +44,24 @@ module RailsStuff
44
44
  extend self
45
45
 
46
46
  # Parses value with specified block. Reraises occured error with Error.
47
- def parse(val)
48
- yield(val) unless val.nil?
49
- rescue => e
47
+ def parse(val, *args, &block)
48
+ parse_not_blank(val, *args, &block)
49
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
50
50
  raise Error.new(e.message, val), nil, e.backtrace
51
51
  end
52
52
 
53
53
  # Parses each value in array with specified block.
54
54
  # Returns `nil` if `val` is not an array.
55
- def parse_array(val)
56
- parse(val) { val.map { |x| yield x unless x.nil? } } if val.is_a?(Array)
55
+ def parse_array(array, *args, &block)
56
+ return unless array.is_a?(Array)
57
+ parse(array) { array.map { |val| parse_not_blank(val, *args, &block) } }
58
+ end
59
+
60
+ # Parses value with given block only when it is not nil.
61
+ # Empty string is converted to nil. Pass `allow_blank: true` to return it as is.
62
+ def parse_not_blank(val, allow_blank: false)
63
+ return if val.nil? || !allow_blank && val.is_a?(String) && val.blank?
64
+ yield(val)
57
65
  end
58
66
 
59
67
  # :method: parse_int
@@ -76,19 +84,9 @@ module RailsStuff
76
84
  #
77
85
  # Parses array of floats. Returns `nil` if `val` is not an array.
78
86
 
79
- # :method: parse_string
80
- # :call-seq: parse_string(val)
81
- #
82
- # Parse string value.
83
-
84
- # :method: parse_string_array
85
- # :call-seq: parse_string_array(val)
86
- #
87
- # Parses array of strings. Returns `nil` if `val` is not an array.
88
-
89
87
  # Parsers for generic types, which are implemented with #to_i, #to_f & #to_s
90
88
  # methods.
91
- %w(string int float).each do |type|
89
+ %w[int float].each do |type|
92
90
  block = :"to_#{type[0]}".to_proc
93
91
 
94
92
  define_method "parse_#{type}" do |val|
@@ -100,6 +98,26 @@ module RailsStuff
100
98
  end
101
99
  end
102
100
 
101
+ # Parse string value.
102
+ def parse_string(val)
103
+ parse(val, allow_blank: true, &:to_s)
104
+ end
105
+
106
+ # Parses array of strings. Returns `nil` if `val` is not an array.
107
+ def parse_string_array(val)
108
+ parse_array(val, allow_blank: true, &:to_s)
109
+ end
110
+
111
+ # Parse decimal value.
112
+ def parse_decimal(val)
113
+ parse(val) { |x| BigDecimal.new(x) }
114
+ end
115
+
116
+ # Parses array of decimals. Returns `nil` if `val` is not an array.
117
+ def parse_decimal_array(val)
118
+ parse_array(val) { |x| BigDecimal.new(x) }
119
+ end
120
+
103
121
  # Parse boolean using ActiveResord's parser.
104
122
  def parse_boolean(val)
105
123
  parse(val) do
@@ -125,7 +143,7 @@ module RailsStuff
125
143
 
126
144
  # Parse JSON string.
127
145
  def parse_json(val)
128
- parse(val) { JSON.parse(val) if val.present? }
146
+ parse(val) { JSON.parse(val) }
129
147
  end
130
148
  end
131
149
  end
@@ -40,7 +40,8 @@ module RailsStuff
40
40
  begin
41
41
  raise 'Available only for persisted record' unless persisted?
42
42
  transaction(requires_new: true) do
43
- update_column field, self.class.send(generate_method, self)
43
+ new_value = self.class.send(generate_method, self)
44
+ update_column field, new_value # rubocop:disable Rails/SkipsModelValidations
44
45
  end
45
46
  rescue ActiveRecord::RecordNotUnique
46
47
  attempt += 1
@@ -43,7 +43,7 @@ module RailsStuff
43
43
  # Set redis_set_options.
44
44
 
45
45
  # Setters that overrides methods, so new values are inherited without recursive `super`.
46
- [:redis_pool, :redis_set_options].each do |name|
46
+ %i[redis_pool redis_set_options].each do |name|
47
47
  define_method "#{name}=" do |val|
48
48
  singleton_class.class_eval do
49
49
  remove_possible_method(name)
@@ -119,7 +119,7 @@ module RailsStuff
119
119
  def resource_params
120
120
  @_resource_params ||= begin
121
121
  key = self.class.resource_param_name
122
- params.permit(key => permitted_attrs)[key] || params.class.new
122
+ params.permit(key => permitted_attrs)[key] || params.class.new.permit!
123
123
  end
124
124
  end
125
125
 
@@ -2,15 +2,6 @@ module RailsStuff
2
2
  module ResourcesController
3
3
  # Defines resource helper and finder method.
4
4
  module ResourceHelper
5
- class << self
6
- def deprecation
7
- @deprecation ||= begin
8
- require 'active_support/deprecation'
9
- ActiveSupport::Deprecation.new('0.7', 'RailsStuff')
10
- end
11
- end
12
- end
13
-
14
5
  # Defines protected helper method. Ex. for `:user`
15
6
  #
16
7
  # helper_method :user
@@ -26,7 +17,7 @@ module RailsStuff
26
17
  #
27
18
  # rubocop:disable CyclomaticComplexity, PerceivedComplexity, AbcSize
28
19
  def resource_helper(name, param: nil, source: nil, **options)
29
- ResourceHelper.deprecation.warn('use :source instead of :class') if options.key?(:class)
20
+ RailsStuff.deprecation_07.warn('use :source instead of :class') if options.key?(:class)
30
21
 
31
22
  param ||= name.to_s.foreign_key.to_sym
32
23
  define_method("#{name}?") { params.key?(param) }
@@ -4,6 +4,8 @@ module RailsStuff
4
4
  module ResourcesController
5
5
  # Helper methods for controllers which works with STI models.
6
6
  module StiHelpers
7
+ class InvalidType < StandardError; end
8
+
7
9
  extend ActiveSupport::Concern
8
10
 
9
11
  module ClassMethods
@@ -12,15 +14,28 @@ module RailsStuff
12
14
  # By default it uses `.types_list` or `.descendants` to get list of
13
15
  # classes and indexes them by class names.
14
16
  def resource_class_by_type
15
- @resource_class_by_type ||= begin
17
+ @resource_class_by_type ||=
16
18
  if resource_class.respond_to?(:types_list)
17
19
  resource_class.types_list
18
20
  else
19
21
  resource_class.descendants
20
22
  end.index_by(&:name)
21
- end
22
23
  end
23
24
 
25
+ attr_writer :resource_class_by_type
26
+
27
+ def resource_class_for(name)
28
+ return resource_class unless name
29
+ resource_class_by_type[name] ||
30
+ if use_resource_class_for_invalid_type
31
+ resource_class
32
+ else
33
+ raise(InvalidType, "No type mapped for #{name.inspect}")
34
+ end
35
+ end
36
+
37
+ attr_accessor :use_resource_class_for_invalid_type
38
+
24
39
  # Class-level accessor to permitted attributes for specisic class.
25
40
  def permitted_attrs_for
26
41
  @permitted_attrs_for ||= Hash.new { |h, k| h[k] = [] }
@@ -41,15 +56,14 @@ module RailsStuff
41
56
  if params.key?(:id)
42
57
  resource.class
43
58
  else
44
- name = params.require(self.class.resource_param_name).
45
- permit(:type)[:type]
46
- self.class.resource_class_by_type[name] ||
47
- raise(ActiveRecord::RecordNotFound)
59
+ key = self.class.resource_param_name
60
+ name = params.permit(key => [:type])[key].try!(:[], :type)
61
+ self.class.resource_class_for(name)
48
62
  end
49
63
  end
50
64
 
51
65
  # Instantiates object using class_from_request.
52
- def build_resource
66
+ def build_resource(attrs = resource_params)
53
67
  @_resource = super.becomes!(class_from_request)
54
68
  end
55
69
 
@@ -11,7 +11,7 @@ module RailsStuff
11
11
  # Single endpoint for multiple seups. Use `:only` and `:except` options
12
12
  # to filter actions.
13
13
  def setup(only: nil, except: nil)
14
- items = instance_methods.map(&:to_s) - %w(setup)
14
+ items = instance_methods.map(&:to_s) - %w[setup]
15
15
  items -= Array.wrap(except).map(&:to_s) if except
16
16
  if only
17
17
  only = Array.wrap(only).map(&:to_s)
@@ -21,13 +21,13 @@ module RailsStuff
21
21
  items.uniq.each { |item| public_send(item) }
22
22
  end
23
23
 
24
- %w(
24
+ %w[
25
25
  concurrency
26
26
  groups/request
27
27
  groups/feature
28
28
  matchers/be_valid_js
29
29
  matchers/redirect_with_turbolinks
30
- ).each do |file|
30
+ ].each do |file|
31
31
  define_method(file) { require "rails_stuff/rspec_helpers/#{file}" }
32
32
  end
33
33
 
@@ -52,7 +52,7 @@ module RailsStuff
52
52
  config.database_cleaner_strategy = {feature: :truncation}
53
53
  config.database_cleaner_strategy.default = :transaction
54
54
  config.add_setting :database_cleaner_options
55
- config.database_cleaner_options = {truncation: {except: %w(spatial_ref_sys)}}
55
+ config.database_cleaner_options = {truncation: {except: %w[spatial_ref_sys]}}
56
56
  config.add_setting :database_cleaner_args
57
57
  config.database_cleaner_args = ->(ex) do
58
58
  strategy = ex.metadata[:concurrent] && :truncation
@@ -6,7 +6,7 @@ module RailsStuff
6
6
  extend self
7
7
 
8
8
  def setup(only: nil, except: nil)
9
- items = instance_methods.map(&:to_s) - %w(setup)
9
+ items = instance_methods.map(&:to_s) - %w[setup]
10
10
  items -= Array.wrap(except).map(&:to_s) if except
11
11
  if only
12
12
  only = Array.wrap(only).map(&:to_s)
@@ -16,10 +16,10 @@ module RailsStuff
16
16
  items.each { |item| public_send(item) }
17
17
  end
18
18
 
19
- %w(
19
+ %w[
20
20
  integration_session
21
21
  response
22
- ).each do |file|
22
+ ].each do |file|
23
23
  define_method(file.tr('/', '_')) { require "rails_stuff/test_helpers/#{file}" }
24
24
  end
25
25
 
@@ -0,0 +1,66 @@
1
+ module RailsStuff
2
+ # Generates writers which apply given transfromer for values.
3
+ module TransformAttrs
4
+ class << self
5
+ def transformations
6
+ @transformations ||= {}
7
+ end
8
+
9
+ # Register new transformation with given block.
10
+ #
11
+ # number_regexp = /\A\d+\z/
12
+ # RailsStuff::TransformAttrs.register :phone do |val|
13
+ # if val && val.to_s =~ number_regexp
14
+ # ActiveSupport::NumberHelper.number_to_phone(val)
15
+ # else
16
+ # val
17
+ # end
18
+ # end
19
+ def register(name, &block)
20
+ transformations[name] = block
21
+ end
22
+
23
+ def fetch_block(ids)
24
+ if ids.is_a?(Array)
25
+ blocks = ids.map { |x| transformations.fetch(x) }
26
+ ->(val) { blocks.reduce(val) { |x, block| block.call(x) } }
27
+ else
28
+ transformations.fetch(ids)
29
+ end
30
+ end
31
+ end
32
+
33
+ register(:strip) { |val| val && val.to_s.strip }
34
+ register(:nullify, &:presence)
35
+ register(:strip_and_nullify) { |val| val && val.to_s.strip.presence }
36
+
37
+ # Options:
38
+ #
39
+ # - `with` - use built-in transfromers from TransformAttrs.transformations.
40
+ # Add new transformations with TransformAttrs.register.
41
+ # - `new_module` - create new module for generated methods.
42
+ # Accepts `:prepend` or `:include`. By default it uses single module
43
+ # which is prepended.
44
+ #
45
+ # transform_attrs(:attr1, :attr2) { |x| x.to_s.downcase }
46
+ # transform_attrs(:attr3, &:presence) # to nullify blanks
47
+ # transform_attrs(:attr4, with: :strip)
48
+ # transform_attrs(:attr4, with: [:strip, :nullify])
49
+ # transform_attrs(:attr5, new_module: :include)
50
+ def transform_attrs(*attrs, with: nil, new_module: false, &block)
51
+ block ||= TransformAttrs.fetch_block(with)
52
+ mod = Module.new.tap { |x| public_send(new_module, x) } if new_module
53
+ mod ||= transform_attrs_methods
54
+ mod.class_eval do
55
+ attrs.each do |attr|
56
+ define_method("#{attr}=") { |val| super(block[val]) }
57
+ end
58
+ end
59
+ end
60
+
61
+ # Module to store generated methods, so they can be overriden in model.
62
+ def transform_attrs_methods
63
+ @transform_attrs_methods ||= Module.new.tap { |x| prepend x }
64
+ end
65
+ end
66
+ end
@@ -1,5 +1,4 @@
1
1
  require 'active_support/core_ext/class/attribute'
2
- require 'active_support/deprecation'
3
2
 
4
3
  module RailsStuff
5
4
  # Adds `types_list` method which tracks all descendants.
@@ -43,15 +42,6 @@ module RailsStuff
43
42
  types_list.delete self
44
43
  end
45
44
 
46
- # Shortcut to eager load all descendants.
47
- def eager_load_types!(dir = nil)
48
- RequireNested.require_nested(dir || 2) # skip 1 more because of deprecation
49
- end
50
-
51
- ActiveSupport::Deprecation.deprecate_methods self,
52
- deprecator: ActiveSupport::Deprecation.new('0.6', 'RailsStuff'),
53
- eager_load_types!: 'Use RequireNested.require_nested instead'
54
-
55
45
  # Tracks all descendants automatically.
56
46
  def inherited(base)
57
47
  super
@@ -7,7 +7,7 @@ module RailsStuff
7
7
  MAJOR = 0
8
8
  MINOR = 6
9
9
  TINY = 0
10
- PRE = 'rc1'.freeze
10
+ PRE = 'rc2'.freeze
11
11
 
12
12
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
13
13
 
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  lib = File.expand_path('../lib', __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'rails_stuff/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_stuff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0.rc1
4
+ version: 0.6.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Melentiev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-13 00:00:00.000000000 Z
11
+ date: 2017-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -80,7 +80,8 @@ files:
80
80
  - bin/install_git_hooks
81
81
  - bin/setup
82
82
  - gemfiles/rails_4.gemfile
83
- - gemfiles/rails_5.gemfile
83
+ - gemfiles/rails_5_0.gemfile
84
+ - gemfiles/rails_5_1.gemfile
84
85
  - lib/assets/javascripts/rails_stuff/plugin_manager.coffee
85
86
  - lib/assets/stylesheets/rails_stuff/_media_queries.scss
86
87
  - lib/net/http/debug.rb
@@ -131,6 +132,7 @@ files:
131
132
  - lib/rails_stuff/test_helpers/concurrency.rb
132
133
  - lib/rails_stuff/test_helpers/integration_session.rb
133
134
  - lib/rails_stuff/test_helpers/response.rb
135
+ - lib/rails_stuff/transform_attrs.rb
134
136
  - lib/rails_stuff/types_tracker.rb
135
137
  - lib/rails_stuff/url_for_keeping_params.rb
136
138
  - lib/rails_stuff/version.rb