trafaret 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trafaret.rb +26 -65
- data/lib/trafaret/base.rb +70 -0
- data/lib/trafaret/errors.rb +9 -0
- data/lib/trafaret/validator.rb +33 -0
- data/lib/trafaret/validators.rb +65 -0
- data/lib/trafaret/version.rb +1 -1
- data/spec/trafaret_spec.rb +41 -11
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc7865262c4ddd22e53d71b22cb53aa70b53f403
|
4
|
+
data.tar.gz: f5fe1c37f11b712d536e3fdb6de0c0189f0fa31e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3021461ace4f7c6df04852525cdd60a8fb161f1915d641b6493cc3da3253e4fba8d21e6e3271e9e5cdbfcce4cb353f99c71b7c269366950100116e292063b1d
|
7
|
+
data.tar.gz: d9cca1a58733a9d30c4b8917e0e0f6b01666f3f8b82611957a727b365949992b59510c17e149725c64a6d84eb86a7fcadd315129ceda85bb3aa77a9bd0ecf75e
|
data/lib/trafaret.rb
CHANGED
@@ -1,76 +1,37 @@
|
|
1
|
-
require
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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,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
|
data/lib/trafaret/version.rb
CHANGED
data/spec/trafaret_spec.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require 'trafaret'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
4
|
+
class ProviderTrafaret < Trafaret::Base
|
5
|
+
key :url, Trafaret::String, min_length: 3, max_length: 50
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
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
|
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-
|
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
|