valle 0.0.1 → 0.0.2

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.
@@ -0,0 +1,11 @@
1
+ ## 0.0.2 / 2012-12-11
2
+
3
+ * fixed inherited behavior; switched to valid? method (Fixes #3) [Anton Kalyaev]
4
+ * added support for integer columns [Anton Kalyaev]
5
+ * added 3 types of columns: character_limited, byte_limited and unlimited [Anton Kalyaev]
6
+ * removed engine [Anton Kalyaev]
7
+ * fix typos in README.md [Aleksandr Ivanov]
8
+
9
+ ## 0.0.1 / 2012-12-09
10
+
11
+ * Initial release (with basic strings support)
data/README.md CHANGED
@@ -9,14 +9,14 @@ hands.
9
9
 
10
10
  validates :field_name, length: { maximum: 255 }
11
11
 
12
- Note: If you do not do this (and usually you are) and try to enter 2147483648 into the field with type: `interger` (see [Numeric types](http://www.postgresql.org/docs/9.2/static/datatype-numeric.html) section of PostgreSQL docs), you will get 500 error.
12
+ Note: If you do not do this (and usually you are) and try to enter 2147483648 into the field with type: `integer` (see [Numeric types](http://www.postgresql.org/docs/9.2/static/datatype-numeric.html) section of PostgreSQL docs), you will get 500 error.
13
13
 
14
14
  Example:
15
15
 
16
16
  PG::Error: ERROR: value "2147483648" is out of range for type integer
17
17
  : SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1
18
18
 
19
- There is a simular gem, called [validates_lengths_from_database](http://github.com/rubiety/validates_lengths_from_database). It solves only one part -
19
+ There is a similar gem, called [validates_lengths_from_database](http://github.com/rubiety/validates_lengths_from_database). It solves only one part -
20
20
  applicable to strings. This gem is designed to work with all possible field types.
21
21
 
22
22
  ## Installation
@@ -59,12 +59,16 @@ Also, you should be able to turn it off temporary by setting `enabled` option to
59
59
  5. Push to the branch (`git push origin my-new-feature`)
60
60
  6. Create new Pull Request
61
61
 
62
- ## Core team
62
+ ## Credits
63
+
64
+ Team members:
63
65
 
64
66
  - [Anton Kalyaev](http://github.com/akalyaev)
65
67
  - [Andrew Kulakov](http://github.com/Andrew8xx8)
66
68
  - [Alexander Kirillov](http://github.com/saratovsource)
67
69
 
70
+ Thank you to all our amazing [contributors](http://github.com/kaize/valle/contributors)!
71
+
68
72
  ## License
69
73
 
70
74
  Valle is released under the [MIT License](http://www.opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'cucumber/rake/task'
5
5
 
6
6
  Rake::TestTask.new do |t|
7
7
  t.libs << "test"
8
- t.test_files = FileList['test/lib/*_test.rb']
8
+ t.test_files = FileList['test/lib/**/*_test.rb']
9
9
  t.verbose = true
10
10
  end
11
11
 
@@ -11,6 +11,8 @@ Feature: adds validators
11
11
  def self.up
12
12
  create_table :users do |t|
13
13
  t.string :name
14
+ t.text :bio
15
+ t.integer :age
14
16
  end
15
17
  end
16
18
  end
@@ -23,12 +25,14 @@ Feature: adds validators
23
25
  """
24
26
 
25
27
  @disable-bundler
26
- Scenario: generate a rails 3 application and use factory definitions
28
+ Scenario: generate a rails 3 application and try out automatically injected validations
27
29
  When I write to "test/factories.rb" with:
28
30
  """
29
31
  FactoryGirl.define do
30
32
  factory :user do
31
33
  name "John"
34
+ bio "A nice write up about this guy"
35
+ age 22
32
36
  end
33
37
  end
34
38
  """
@@ -4,24 +4,21 @@ module Valle
4
4
  extend Configuration
5
5
 
6
6
  # core
7
- autoload :BoundMapper, 'valle/bound_mapper'
8
7
  autoload :BoundsManager, 'valle/bounds_manager'
9
8
  autoload :ValidationSetter, 'valle/validation_setter'
10
9
 
10
+ # extensions
11
+ module AbstractAdapter
12
+ autoload :ColumnWrapper, 'valle/abstract_adapter/column_wrapper'
13
+ autoload :AbstractColumn, 'valle/abstract_adapter/abstract_column'
14
+ autoload :ByteLimitedColumn, 'valle/abstract_adapter/byte_limited_column'
15
+ autoload :CharacterLimitedColumn, 'valle/abstract_adapter/character_limited_column'
16
+ autoload :UnlimitedColumn, 'valle/abstract_adapter/unlimited_column'
17
+ end
18
+
11
19
  # hooks
12
20
  autoload :Hooks, 'valle/hooks'
13
21
  end
14
22
 
15
- # load Rails/Railtie
16
- begin
17
- require 'rails'
18
- rescue LoadError
19
- #do nothing
20
- end
21
-
22
- # if not using Railtie, call `Valle::Hooks.init` directly
23
- # TODO [AK 09/12/12] move this block to initializers
24
- if defined? Rails
25
- require 'valle/railtie'
26
- require 'valle/engine'
27
- end
23
+ ## if not using Railtie, call `Valle::Hooks.init` directly
24
+ require 'valle/railtie' if defined? Rails
@@ -0,0 +1,48 @@
1
+ module Valle
2
+ module AbstractAdapter
3
+ class AbstractColumn
4
+
5
+ ##
6
+ # Adds more functionality to the standard ActiveRecord::ConnectionAdapters::Column
7
+ #
8
+ # @param [ActiveRecord::ConnectionAdapters::Column] original_column the original column
9
+ #
10
+ # @example
11
+ # c = AbstractAdapter::AbstractColumn.new(original_column)
12
+ #
13
+ # c.minimum
14
+ # => -128
15
+ # c.maximum
16
+ # => 127
17
+ #
18
+ def initialize(original_column)
19
+ @original_column = original_column
20
+ end
21
+
22
+ ##
23
+ # Proxy all methods missing to original column
24
+ #
25
+ def method_missing(method_name, *arguments, &block)
26
+ @original_column.send(method_name, *arguments, &block)
27
+ end
28
+
29
+ def respond_to_method_missing?(method_name, include_private = false)
30
+ @original_column.respond_to?(method_name)
31
+ end
32
+
33
+ ##
34
+ # Get maximum possible value/length for this column
35
+ #
36
+ def maximum
37
+ raise NotImplementedError.new("You must implement maximum method.")
38
+ end
39
+
40
+ ##
41
+ # Get minimum value/length for this column
42
+ #
43
+ def minimum
44
+ raise NotImplementedError.new("You must implement minimum method.")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,26 @@
1
+ module Valle
2
+ module AbstractAdapter
3
+ class ByteLimitedColumn < AbstractColumn
4
+
5
+ def maximum
6
+ case limit
7
+ when 1; 127
8
+ when 2; 32767
9
+ when 3; 8388607
10
+ when 4; 2147483647
11
+ when 8; 9223372036854775807
12
+ end
13
+ end
14
+
15
+ def minimum
16
+ case limit
17
+ when 1; -128
18
+ when 2; -32768
19
+ when 3; -8388608
20
+ when 4; -2147483648
21
+ when 8; -9223372036854775808
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ module Valle
2
+ module AbstractAdapter
3
+ class CharacterLimitedColumn < AbstractColumn
4
+
5
+ def maximum
6
+ limit
7
+ end
8
+
9
+ def minimum
10
+ nil
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,55 @@
1
+ module Valle
2
+ module AbstractAdapter
3
+ class ColumnWrapper
4
+
5
+ class << self
6
+
7
+ ##
8
+ # Wraps original column
9
+ #
10
+ # @param [ActiveRecord::ConnectionAdapters::Column] original_column the original column
11
+ #
12
+ def wrap(original_column)
13
+ case
14
+ when limit_in_bytes?(original_column)
15
+ ByteLimitedColumn.new(original_column)
16
+ when limit_in_characters?(original_column)
17
+ CharacterLimitedColumn.new(original_column)
18
+ else
19
+ UnlimitedColumn.new(original_column)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ ##
26
+ # Determines whether the limit's method returned value is count of bytes
27
+ #
28
+ # Limit is number of bytes for :binary and :integer columns.
29
+ # @see http://apidock.com/rails/ActiveRecord/ConnectionAdapters/TableDefinition/column
30
+ #
31
+ def limit_in_bytes?(column)
32
+ case column.type
33
+ # when :binary; true
34
+ when :integer; true
35
+ else false
36
+ end
37
+ end
38
+
39
+ ##
40
+ # Determines whether the limit's method returned value is count of characters
41
+ #
42
+ # Limit is number of characters for :string and :text columns
43
+ # @see http://apidock.com/rails/ActiveRecord/ConnectionAdapters/TableDefinition/column
44
+ #
45
+ def limit_in_characters?(column)
46
+ case column.type
47
+ when :string; true
48
+ when :text; true
49
+ else false
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,12 @@
1
+ module Valle
2
+ module AbstractAdapter
3
+ class UnlimitedColumn < AbstractColumn
4
+
5
+ def maximum
6
+ end
7
+
8
+ def minimum
9
+ end
10
+ end
11
+ end
12
+ end
@@ -6,19 +6,13 @@ module Valle
6
6
  ##
7
7
  # Add validators for all columns of a given class
8
8
  #
9
- # 2 steps:
10
- # 1) get bound for the column
11
- # 2) set validation
12
- #
13
9
  # @param [ActiveRecord::Base] klass the AR model class
14
10
  #
15
11
  def add_validators(klass)
16
- mapper = BoundMapper.new
17
-
18
12
  columns = klass.columns
19
- columns.each do |column|
20
- bound = mapper.bound(column)
21
- ValidationSetter.add_validator(bound, column, klass)
13
+ columns.each do |original_column|
14
+ column = AbstractAdapter::ColumnWrapper.wrap(original_column)
15
+ ValidationSetter.add_validator(column, klass)
22
16
  end
23
17
  end
24
18
  end
@@ -3,17 +3,51 @@ module Valle
3
3
 
4
4
  class << self
5
5
 
6
+ ##
7
+ # Runs all the hooks, required for this gem
8
+ #
6
9
  def init
7
10
  ActiveSupport.on_load(:active_record) do
8
- ActiveRecord::Base.class_eval do
9
- # TODO [AK 09/12/12] possible we should run it after the class was inherited
10
- # @see http://stackoverflow.com/q/7093992/820520
11
- def self.inherited(subclass)
12
- Valle::BoundsManager.add_validators(subclass)
11
+ Valle::Hooks.extend_inherited_method
12
+ end
13
+ end
14
+
15
+ ##
16
+ # Extends the functionality of inherited method
17
+ #
18
+ def extend_inherited_method
19
+ ActiveRecord::Base.class_eval do
20
+ class << self
21
+ def inherited_with_valle_validators(subclass)
22
+ inherited_without_valle_validators(subclass)
23
+ Valle::Hooks.extend_ar_validations_valid_method(subclass)
13
24
  end
25
+
26
+ alias_method_chain :inherited, :valle_validators
14
27
  end
15
28
  end
16
29
  end
30
+
31
+ ##
32
+ # Extends the functionality of ActiveRecord::Validations valid? method
33
+ #
34
+ # @param [ActiveRecord::Base] subclass the AR::Base child class
35
+ # @note ActiveRecord::Validations should be defined at this point
36
+ #
37
+ def extend_ar_validations_valid_method(subclass)
38
+ subclass.instance_eval do
39
+ cattr_accessor :valle_validators
40
+ end
41
+
42
+ subclass.class_eval do
43
+ def valid_with_valle_validators?(context = nil)
44
+ self.class.valle_validators ||= Valle::BoundsManager.add_validators(self.class)
45
+ valid_without_valle_validators?(context)
46
+ end
47
+
48
+ alias_method_chain :valid?, :valle_validators
49
+ end
50
+ end
17
51
  end
18
52
  end
19
53
  end
@@ -5,14 +5,20 @@ module Valle
5
5
  ##
6
6
  # Adds validator to the klass column depending on its type
7
7
  #
8
- # @param [Bound] bound the bound
9
- # @param [Column] column the column
8
+ # @param [AbstractAdapter::AbstractColumn] column the column
10
9
  # @param [ActiveRecord::Base] klass the AR model class
11
10
  #
12
- def add_validator(bound, column, klass)
11
+ def add_validator(column, klass)
12
+ options = {}
13
+ options[:minimum] = column.minimum if column.minimum
14
+ options[:maximum] = column.maximum if column.maximum
15
+ return false unless options.present?
16
+
13
17
  case column.type
14
- when :string
15
- klass.validates column.name, length: { maximum: bound.maximum }
18
+ when :string, :text
19
+ klass.validates column.name, length: options
20
+ when :integer
21
+ klass.validates column.name, numericality: options
16
22
  end
17
23
  end
18
24
  end
@@ -1,3 +1,3 @@
1
1
  module Valle
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,25 @@
1
+ require "test_helper"
2
+
3
+ class CharacterLimitedColumnTest < TestCase
4
+
5
+ def test_maximum_should_return_value_for_string_column
6
+ original_column = ::ActiveRecord::ConnectionAdapters::Column.new("test_column", "", "string(255)")
7
+ column = Valle::AbstractAdapter::CharacterLimitedColumn.new(original_column)
8
+
9
+ assert column.maximum
10
+ end
11
+
12
+ def test_maximum_should_return_correct_value_for_string_column_if_user_redefine_limit
13
+ original_column = ::ActiveRecord::ConnectionAdapters::Column.new("test_column", "", "string(200)")
14
+ column = Valle::AbstractAdapter::CharacterLimitedColumn.new(original_column)
15
+
16
+ assert_equal 200, column.maximum
17
+ end
18
+
19
+ def test_minimum_should_return_nil
20
+ original_column = ::ActiveRecord::ConnectionAdapters::Column.new("test_column", "", "string")
21
+ column = Valle::AbstractAdapter::CharacterLimitedColumn.new(original_column)
22
+
23
+ assert_nil column.minimum
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require "test_helper"
2
+ require "active_record"
3
+
4
+ class ColumnWrapperTest < TestCase
5
+
6
+ def test_wrap_should_return_instance_of_character_limited_column_for_string_column
7
+ column = ::ActiveRecord::ConnectionAdapters::Column.new("test_column", "", "string")
8
+ wrapped_column = Valle::AbstractAdapter::ColumnWrapper.wrap(column)
9
+
10
+ assert wrapped_column.is_a?(Valle::AbstractAdapter::CharacterLimitedColumn)
11
+ end
12
+
13
+ def test_wrap_should_return_instance_of_byte_limited_column_for_int_column
14
+ column = ::ActiveRecord::ConnectionAdapters::Column.new("test_column", "", "int")
15
+ wrapped_column = Valle::AbstractAdapter::ColumnWrapper.wrap(column)
16
+
17
+ assert wrapped_column.is_a?(Valle::AbstractAdapter::ByteLimitedColumn)
18
+ end
19
+ end
@@ -1,6 +1,8 @@
1
1
  require 'bundler/setup'
2
2
  Bundler.require
3
3
 
4
+ require "active_record"
5
+
4
6
  MiniTest::Unit.autorun
5
7
 
6
8
  class TestCase < MiniTest::Unit::TestCase
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-09 00:00:00.000000000 Z
12
+ date: 2012-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -53,6 +53,7 @@ extra_rdoc_files: []
53
53
  files:
54
54
  - .gitignore
55
55
  - .travis.yml
56
+ - CHANGELOG.md
56
57
  - Gemfile
57
58
  - Guardfile
58
59
  - LICENSE
@@ -62,15 +63,19 @@ files:
62
63
  - features/step_definitions/rails_steps.rb
63
64
  - features/support/env.rb
64
65
  - lib/valle.rb
65
- - lib/valle/bound_mapper.rb
66
+ - lib/valle/abstract_adapter/abstract_column.rb
67
+ - lib/valle/abstract_adapter/byte_limited_column.rb
68
+ - lib/valle/abstract_adapter/character_limited_column.rb
69
+ - lib/valle/abstract_adapter/column_wrapper.rb
70
+ - lib/valle/abstract_adapter/unlimited_column.rb
66
71
  - lib/valle/bounds_manager.rb
67
72
  - lib/valle/configuration.rb
68
- - lib/valle/engine.rb
69
73
  - lib/valle/hooks.rb
70
74
  - lib/valle/railtie.rb
71
75
  - lib/valle/validation_setter.rb
72
76
  - lib/valle/version.rb
73
- - test/lib/bound_mapper_test.rb
77
+ - test/lib/abstract_adapter/character_limited_column_test.rb
78
+ - test/lib/abstract_adapter/column_wrapper_test.rb
74
79
  - test/test_helper.rb
75
80
  - valle.gemspec
76
81
  homepage: http://github.com/kaize/valle
@@ -87,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
92
  version: '0'
88
93
  segments:
89
94
  - 0
90
- hash: -1528972839465003213
95
+ hash: 1761133230881238709
91
96
  required_rubygems_version: !ruby/object:Gem::Requirement
92
97
  none: false
93
98
  requirements:
@@ -96,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
101
  version: '0'
97
102
  segments:
98
103
  - 0
99
- hash: -1528972839465003213
104
+ hash: 1761133230881238709
100
105
  requirements: []
101
106
  rubyforge_project:
102
107
  rubygems_version: 1.8.24
@@ -108,5 +113,6 @@ test_files:
108
113
  - features/adds_validators.feature
109
114
  - features/step_definitions/rails_steps.rb
110
115
  - features/support/env.rb
111
- - test/lib/bound_mapper_test.rb
116
+ - test/lib/abstract_adapter/character_limited_column_test.rb
117
+ - test/lib/abstract_adapter/column_wrapper_test.rb
112
118
  - test/test_helper.rb
@@ -1,36 +0,0 @@
1
- module Valle
2
-
3
- Bound = Struct.new :minimum, :maximum
4
-
5
- class BoundMapper
6
-
7
- ##
8
- # Returns a new bound for the column
9
- #
10
- # @param [Column] column the column
11
- #
12
- def bound(column)
13
- Bound.new minimum(column), maximum(column)
14
- end
15
-
16
- private
17
-
18
- ##
19
- # Get the lower limit for a given column
20
- #
21
- # @param [Column] column the column
22
- #
23
- def minimum(column)
24
-
25
- end
26
-
27
- ##
28
- # Get the upper limit for a given column
29
- #
30
- # @param [Column] column the column
31
- #
32
- def maximum(column)
33
- column.limit
34
- end
35
- end
36
- end
@@ -1,4 +0,0 @@
1
- module Valle#:nodoc:
2
- class Engine < ::Rails::Engine #:nodoc:
3
- end
4
- end
@@ -1,21 +0,0 @@
1
- require "test_helper"
2
- require "active_record"
3
-
4
- class BoundMapperTest < TestCase
5
-
6
- def setup
7
- @bound_mapper = Valle::BoundMapper.new
8
- end
9
-
10
- def test_should_return_bound
11
- column = ::ActiveRecord::ConnectionAdapters::Column.new("test_column", "")
12
- assert @bound_mapper.bound(column), "Bound for column '#{column.name}' not found"
13
- end
14
-
15
- def test_should_return_maximum_for_column_with_type_string
16
- column = ::ActiveRecord::ConnectionAdapters::Column.new("test_column", "", "string(255)")
17
- bound = @bound_mapper.bound(column)
18
-
19
- assert_equal 255, bound.maximum
20
- end
21
- end