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 +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
|