trafaret 1.0.1 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a6f9ebc15fa44c667060779f703eb99d2462d83
4
- data.tar.gz: 82a0675c08400058c321efa24851b6a0e9d2a66f
3
+ metadata.gz: bc7865262c4ddd22e53d71b22cb53aa70b53f403
4
+ data.tar.gz: f5fe1c37f11b712d536e3fdb6de0c0189f0fa31e
5
5
  SHA512:
6
- metadata.gz: cd413ceeafc1db8704c047a81e8bb72d56404183cd5c62c446bdafc8652be4a7b6469b4b3821e4346155b8dfae2f35207c91d3eba9558d19ffcb28bc8824a8e1
7
- data.tar.gz: 7e978fa7abe98d587cd85985fc18fc862e2c298457eba0b65f8d59afd47f57f8c58e2b3968abada01be6f5e321edc4adf3360443112203bf7a22b6627b2433d1
6
+ metadata.gz: d3021461ace4f7c6df04852525cdd60a8fb161f1915d641b6493cc3da3253e4fba8d21e6e3271e9e5cdbfcce4cb353f99c71b7c269366950100116e292063b1d
7
+ data.tar.gz: d9cca1a58733a9d30c4b8917e0e0f6b01666f3f8b82611957a727b365949992b59510c17e149725c64a6d84eb86a7fcadd315129ceda85bb3aa77a9bd0ecf75e
data/lib/trafaret.rb CHANGED
@@ -1,76 +1,37 @@
1
- require "trafaret/version"
1
+ require 'active_support/core_ext'
2
+ require 'trafaret/version'
3
+ require 'trafaret/errors'
4
+ require 'trafaret/validator'
5
+ require 'trafaret/validators'
6
+ require 'trafaret/base'
2
7
 
3
8
  module Trafaret
4
- class Attribute
5
- def initialize(name, options = {}, &blk)
6
- @name = name
7
- @options = options
8
- @blk = blk
9
+ def self.get_validator(validator)
10
+ if validator.is_a? Symbol
11
+ class_name = validator.to_s.classify
12
+ validator = Trafaret.const_get(class_name) rescue nil
13
+ validator ||= Kernel.const_get(class_name)
14
+ else
15
+ validator
9
16
  end
10
-
11
- def name
12
- @name.to_s
13
- end
14
-
15
- def get(obj)
16
- if @blk
17
- return @blk.call obj
18
- end
19
- data = begin
20
- obj.send(@name)
21
- rescue NameError
22
- nil
23
- end
24
- data ||= begin
25
- obj[@name] || obj[@name.to_s]
26
- rescue NoMethodError, TypeError
27
- nil
28
- end
29
- end
30
-
31
- alias :dump :get
32
17
  end
33
18
 
34
- class Array < Attribute
35
- def dump(obj)
36
- cls = @options[:class]
37
- if data = get(obj)
38
- data.map do |elem|
39
- cls.dump elem
40
- end
41
- else
42
- []
43
- end
44
- end
19
+ def self.get_instantiated_validator(validator, options = {})
20
+ val = self.get_validator(validator)
21
+ val = val.new(options) if val.is_a? Class
22
+ val
45
23
  end
46
24
 
47
- class Hash < Attribute
48
- def initialize(name = nil, options = {}, &blk)
49
- @name = name
50
- @options = options
51
- @attrs = options[:attributes] || []
52
- instance_eval(&blk)
53
- end
54
-
55
- def attribute(name, options = {}, &blk)
56
- @attrs << Attribute.new(name, options, &blk)
57
- end
58
-
59
- def array(name, options = {}, &blk)
60
- @attrs << Array.new(name, options, &blk)
61
- end
62
-
63
- def hash(name, options = {}, &blk)
64
- @attrs << Hash.new(name, options = {}, &blk)
65
- end
25
+ def self.[](validator, options = {})
26
+ return self.get_instantiated_validator(validator, options)
27
+ end
66
28
 
67
- def dump(obj)
68
- res = {}
69
- data = if @name then get(obj) else obj end
70
- @attrs.each do |attr|
71
- res[attr.name] = attr.dump(data)
72
- end
73
- res
29
+ def self.method_missing(meth, *args, &blk)
30
+ cls = self.get_validator(meth)
31
+ if cls
32
+ cls.new(*args, &blk)
33
+ else
34
+ super
74
35
  end
75
36
  end
76
37
  end
@@ -0,0 +1,70 @@
1
+ module Trafaret
2
+ class Key
3
+ def initialize(name, validator, options = {}, &blk)
4
+ @name = name
5
+ @validator = validator.new(options)
6
+ @options = options
7
+ @blk = blk
8
+ end
9
+
10
+ def get(obj, extractors = {})
11
+ return @blk.call obj if @blk
12
+ data = begin
13
+ extractors[@name].call(obj) if extractors[@name]
14
+ rescue NoMethodError
15
+ nil
16
+ end
17
+ data ||= begin
18
+ obj.send(@name)
19
+ rescue NameError
20
+ nil
21
+ end
22
+ data ||= begin
23
+ obj[@name] || obj[@name.to_s]
24
+ rescue NoMethodError, TypeError
25
+ nil
26
+ end
27
+ end
28
+
29
+ def call(data, extractors = {})
30
+ [@name, @validator.call(get(data, extractors), &@blk)]
31
+ end
32
+ end
33
+
34
+ class Extractor
35
+ def initialize(&blk)
36
+ @blk = blk
37
+ end
38
+
39
+ def call(data)
40
+ @blk.call data
41
+ end
42
+ end
43
+
44
+ class Base < Validator
45
+ module ClassMethods
46
+ attr_accessor :keys, :extractors
47
+ def inherited(base)
48
+ base.keys = (keys || []).dup
49
+ base.extractors = (extractors || {}).dup
50
+ end
51
+
52
+ def key(name, validator, options = {}, &blk)
53
+ @keys << Key.new(name, Trafaret.get_validator(validator), options, &blk)
54
+ end
55
+
56
+ def extract(name, &blk)
57
+ @extractors[name] = Extractor.new(&blk)
58
+ end
59
+ end
60
+ extend ClassMethods
61
+
62
+ def validate(data)
63
+ res = []
64
+ self.class.keys.each do |key|
65
+ res << key.call(data, extractors = self.class.extractors)
66
+ end
67
+ Hash[res]
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,9 @@
1
+ module Trafaret
2
+ class Error < Exception
3
+ attr_reader :message
4
+
5
+ def initialize(message)
6
+ @message = message
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ class Trafaret::Validator
2
+ def initialize(options = {})
3
+ @options = options
4
+ end
5
+
6
+ def validate(data)
7
+ data # or return Trafaret::Error
8
+ end
9
+
10
+ def convert(data)
11
+ data
12
+ end
13
+
14
+ def call(data)
15
+ val = validate(data)
16
+ return val if val.is_a? Trafaret::Error
17
+ if block_given?
18
+ yield val
19
+ else
20
+ convert(val)
21
+ end
22
+ end
23
+
24
+ # ADT
25
+ def |(other)
26
+ Trafaret::Or.new(self, other)
27
+ end
28
+
29
+ # Helpers
30
+ def failure(msg)
31
+ Trafaret::Error.new msg
32
+ end
33
+ end
@@ -0,0 +1,65 @@
1
+ module Trafaret
2
+ class Any < Validator
3
+ end
4
+
5
+ class Or < Validator
6
+ attr_reader :validators
7
+
8
+ def initialize(*args)
9
+ args = args.first if args.first.is_a? ::Array
10
+ @validators = args.map { |v| Trafaret.get_instantiated_validator(v) }
11
+ end
12
+
13
+ def validate(data)
14
+ errors = []
15
+ @validators.each do |v|
16
+ res = v.call(data)
17
+ if res.is_a? Trafaret::Error
18
+ errors << res
19
+ else
20
+ return res
21
+ end
22
+ end
23
+ return failure errors
24
+ end
25
+
26
+ def |(other)
27
+ Trafaret::Or.new(*validators, other)
28
+ end
29
+ end
30
+
31
+ class String < Validator
32
+ def validate(data)
33
+ return failure('Not a String') unless data.is_a? ::String
34
+ return failure('Should not be blank') if !@options[:allow_blank] && data.empty?
35
+ return failure('Too short') if @options[:min_length] && data.size < @options[:min_length]
36
+ return failure('Too long') if @options[:max_length] && data.size > @options[:max_length]
37
+ if @options[:regex]
38
+ match = @options[:regex].match(data)
39
+ return failure('Does not match') unless match
40
+ return match
41
+ end
42
+ data
43
+ end
44
+ end
45
+
46
+ class Integer < Validator
47
+ def validate(data)
48
+ data.to_i
49
+ end
50
+ end
51
+
52
+ class Array < Validator
53
+ def self.[](validator, options = {})
54
+ self.new(options.merge(validator: validator))
55
+ end
56
+
57
+ def validate(data)
58
+ return failure('Not an Array') unless data.is_a? ::Array
59
+ cls = Trafaret.get_validator(@options[:validator]).new @options
60
+ data.map do |elem|
61
+ cls.call elem
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,3 +1,3 @@
1
1
  module Trafaret
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -1,20 +1,21 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require 'trafaret'
3
3
 
4
- describe Trafaret do
5
- Provider = Trafaret::Hash.new do
6
- attribute :url
7
- end
4
+ class ProviderTrafaret < Trafaret::Base
5
+ key :url, Trafaret::String, min_length: 3, max_length: 50
6
+ end
8
7
 
9
- Checker = Trafaret::Hash.new do
10
- attribute :name
11
- array :providers, class: Provider do |obj|
12
- obj['oa'].flat_map do |prov_name, accs|
13
- accs.map {|uuid, data| data}
14
- end
8
+ class FacebookResponseTrafaret < Trafaret::Base
9
+ key :name, :string, optional: true, min_length: 2
10
+ extract :providers do |data|
11
+ data['oa'].flat_map do |prov_name, accs|
12
+ accs.map { |uuid, data| data }
15
13
  end
16
14
  end
15
+ key :providers, :array, validator: :provider_trafaret
16
+ end
17
17
 
18
+ describe Trafaret::Base do
18
19
  let :raw do
19
20
  {'name' => 'kuku',
20
21
  'oa' => {
@@ -26,6 +27,35 @@ describe Trafaret do
26
27
  }
27
28
  end
28
29
  it 'should work' do
29
- Checker.dump(raw).should == ({"name"=>"kuku", "providers"=>[{"url"=>"http://ya.ru"}, {"url"=>"http://www.ru"}]})
30
+ FacebookResponseTrafaret.new.call(raw).should == ({name: "kuku", providers: [{url: "http://ya.ru"}, {url: "http://www.ru"}]})
31
+ end
32
+ end
33
+
34
+ describe Trafaret::String do
35
+ it 'should check errors' do
36
+ Trafaret.string.call('').message.should == 'Should not be blank'
37
+ Trafaret.string(min_length: 10).call('abc').message.should == 'Too short'
38
+ Trafaret.string(max_length: 1).call('abc').message.should == 'Too long'
39
+ Trafaret.string(regex: /abc/).call('bca').message.should == 'Does not match'
30
40
  end
31
41
  end
42
+
43
+ describe Trafaret::Array do
44
+ it 'should check' do
45
+ Trafaret::Array[:string].call(['a', 'b', 'c']).should == ['a', 'b', 'c']
46
+ end
47
+ end
48
+
49
+ describe Trafaret::Or do
50
+ it 'should return value' do
51
+ Trafaret[:or, [:string, :integer]].call('krukatuka').should == 'krukatuka'
52
+
53
+ (Trafaret[:string] | Trafaret[:integer]).call('krukatuka').should == 'krukatuka'
54
+
55
+ (Trafaret.string | Trafaret.integer).call('krukatuka').should == 'krukatuka'
56
+ end
57
+
58
+ it 'should return errors' do
59
+ Trafaret[:or, Trafaret[:array, validator: :string]].call('krukatuka').message.first.message.should == 'Not an Array'
60
+ end
61
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trafaret
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikhail Krivushin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-02 00:00:00.000000000 Z
11
+ date: 2014-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,6 +53,10 @@ files:
53
53
  - README.md
54
54
  - Rakefile
55
55
  - lib/trafaret.rb
56
+ - lib/trafaret/base.rb
57
+ - lib/trafaret/errors.rb
58
+ - lib/trafaret/validator.rb
59
+ - lib/trafaret/validators.rb
56
60
  - lib/trafaret/version.rb
57
61
  - spec/trafaret_spec.rb
58
62
  - trafaret.gemspec