yas 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2bc6f995a8dbaa33cabd77eb2a9488ee83e9af68
4
+ data.tar.gz: 9384f3846028776890fc010f4dcda77743f44812
5
+ SHA512:
6
+ metadata.gz: ec347427f0a1fa5adef59b4f49d55328d0060ac6e137faf061dde08f14f7c22617c3d0594448a92dfbf8f961ea9992eae3a0c6197539c1465c09066655b4511c
7
+ data.tar.gz: 83e5eb5b1a739e9402d195784417a20b6fcdb27863a3fc555498a50944ded1cbc84aaf1419ce3283dd9210970b52a1a0c76b671cf152fe821836b4fa14236fd6
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.swp
3
+ *.swo
4
+ tags
5
+ .yardoc
6
+ doc
data/README.markdown ADDED
@@ -0,0 +1,127 @@
1
+ # YAS
2
+
3
+ YAS (Yet Another Schema) is an extensible hash validator for Ruby.
4
+ Using YAS, you can enforce a specific key to be required, rename them, perform automatic type conversion, and other goodies.
5
+
6
+
7
+ ## Installation
8
+
9
+ gem install yas
10
+
11
+
12
+ ## Quick Start
13
+
14
+ require 'yas'
15
+
16
+ class MySchema < YAS::Schema
17
+ rename :foo => :bar
18
+ end
19
+
20
+ h = { bar: "value" }
21
+ h.validate! MySchema
22
+ puts h[:foo] # "value"
23
+ puts h[:bar] # nil
24
+
25
+
26
+ ## Extensions
27
+
28
+ You can extend the behavior of YAS by writing your own custom extensions, but `YAS::Schema` already comes with a set of awesome default extensions that you can immediately use:
29
+
30
+ * `attribute name, &block` or `key name, &block`
31
+
32
+ Declares an attribute/key with various requirements.
33
+
34
+ * `rename`
35
+
36
+ Rename keys.
37
+
38
+ * `migrate`
39
+
40
+ Migrate the value of a key.
41
+
42
+ * `whitelist`
43
+
44
+ Provide a set of keys that you only care to see.
45
+
46
+
47
+ ### Attribute Extension
48
+
49
+ The Attribute extension allows you to specify certain requirements/restrictions for a given key:
50
+
51
+ class MySchema < YAS::Schema
52
+ key :email do
53
+ required
54
+ end
55
+
56
+ key :first_name do
57
+ type String
58
+ end
59
+ end
60
+
61
+ hash = { :first_name => 'John' }
62
+ hash.validate! MySchema # raises YAS::ValidationError "Key 'email' is missing"
63
+ hash.merge!(:email => 'john@email.com')
64
+ hash.validate! MySchema # Success!
65
+
66
+ List of directives you can use:
67
+
68
+ * `required`
69
+
70
+ Sets this key as required. Will raise an error if key is missing.
71
+
72
+ * `type(T)`
73
+
74
+ Sets the type of this key. Will perform type check if specified. Can be nested if type is a YAS::Schema!
75
+
76
+ * `auto_convert`
77
+
78
+ Enables auto-conversion to the specified type. This gets ignored if `type` is not specified.
79
+
80
+ * `default(&block)`
81
+
82
+ Runs the block to set the default value for this key, if it's missing or nil.
83
+
84
+ * `validate_value(&block)`
85
+
86
+ Custom validation method to check the value of a key. This is useful in cases where you only want certain values to be stored (e.g a number between 1-10 only)
87
+
88
+
89
+ ### Rename Extension
90
+
91
+ Using `rename` to rename keys. Useful to maintain hash integrity.
92
+
93
+ class UserSchema < YAS::Schema
94
+ rename :username => :nickname
95
+ end
96
+ hash = { :username => 'jdoe' } )
97
+ hash.validate!(UserSchema)
98
+ hash[:nickname] # 'jdoe'
99
+
100
+
101
+ ### Migrate Extension
102
+
103
+ You can also migrate the values. This is useful if you have hash whose values are in the old format and you want to convert them to the new format.
104
+
105
+ class UserSchema < YAS::Schema
106
+ migrate :nicknames do |v|
107
+ v.class == String ? [v] : v
108
+ end
109
+ end
110
+ hash = { :nicknames => 'jdoe' }
111
+ hash.validate!(UserSchema)
112
+ hash[:nicknames] # ['jdoe']
113
+
114
+
115
+ ### Whitelist Extension
116
+
117
+ Whitelist allows you to remove unneeded keys.
118
+
119
+ class UserSchema < YAS::Schema
120
+ whitelist :name, :address
121
+ end
122
+ hash = { :name => 'jdoe', :address => '123 Main St', :phone => '9990000000', :comment => 'JDoe is cool' }
123
+ hash.validate!(UserSchema)
124
+ hash[:name] # ['jdoe']
125
+ hash[:address] # ['123 Main St']
126
+ hash[:phone] # nil
127
+ hash[:comment] # nil
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rake/testtask'
2
+
3
+ task :default => "test"
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.description = "Run tests"
7
+ t.name = "test"
8
+ t.pattern = "./test/**/*.rb"
9
+ end
10
+
11
+ desc "Build the gemfile"
12
+ task :build do
13
+ `gem build yas.gemspec`
14
+ end
data/lib/yas/errors.rb ADDED
@@ -0,0 +1,9 @@
1
+ module YAS
2
+
3
+ class ValidationError < StandardError
4
+ end
5
+
6
+ class ExtensionError < StandardError
7
+ end
8
+
9
+ end
@@ -0,0 +1,199 @@
1
+ # Defines specific rules for keys
2
+ #
3
+
4
+ class YAS::AttributeExt
5
+
6
+ module ClassMethods
7
+
8
+ def key attr, &block
9
+ attr = attr.to_s.to_sym
10
+ new_attr = Attribute.new(attr)
11
+ new_attr.instance_eval &block if block
12
+ attributes[attr] = new_attr
13
+ new_attr
14
+ end
15
+ alias_method :attribute, :key
16
+
17
+
18
+ def attributes
19
+ @attributes ||= {}
20
+ end
21
+ end
22
+
23
+
24
+ def self.when_used schema
25
+ schema.extend ClassMethods
26
+ end
27
+
28
+
29
+ def self.when_schema_inherited superschema, subschema
30
+ superschema.attributes.each do |key, attr|
31
+ subschema.attributes[key] = attr
32
+ end
33
+ end
34
+
35
+
36
+ def self.apply schema, hash
37
+ schema.attributes.each do |key, attr|
38
+ raise YAS::ValidationError, "Key #{key} is required" if attr.required? && !hash.has_key?(key)
39
+ hash.has_key?(key) and
40
+ hash[key] = attr.validate(hash[key])
41
+ end
42
+ end
43
+
44
+
45
+ class Attribute
46
+
47
+ attr_reader :name
48
+
49
+ @required = false
50
+ @type = nil
51
+ @auto_convert = false
52
+ @default_block = nil
53
+ @check_value_block = nil
54
+
55
+
56
+ def initialize name
57
+ @name = name.to_s.to_sym
58
+ end
59
+
60
+
61
+ # Directive to mark this Attribute as required.
62
+ #
63
+ def required
64
+ @required = true
65
+ self
66
+ end
67
+
68
+
69
+ def required?
70
+ @required
71
+ end
72
+
73
+
74
+ # Directive to enforce the data type of this Attribute.
75
+ #
76
+ def type t
77
+ @type = t
78
+ self
79
+ end
80
+
81
+
82
+ # Attempts to auto convert values to the type specified by the {type}
83
+ # directive if the value is not of the same type.
84
+ # Has no effect if {type} is not specified.
85
+ #
86
+ def auto_convert
87
+ @auto_convert = true
88
+ self
89
+ end
90
+
91
+
92
+ # Directive to set the default value of this Attribute. Once specified, if
93
+ # this Attribute does not exist during the Document initialization, whether
94
+ # that's from {Document.get} or {Document#initialize}, the value of the
95
+ # Attribute will be set to the value returned by the block.
96
+ #
97
+ # @yield Sets the value of this Attribute to the value returned by the
98
+ # block.
99
+ #
100
+ def default &block
101
+ @default_block = block
102
+ self
103
+ end
104
+
105
+
106
+ def has_default?
107
+ @default_block != nil
108
+ end
109
+
110
+
111
+ # Perform a validation over the value of this Attribute.
112
+ #
113
+ # @yield [v] Value of the Attribute.
114
+ #
115
+ # @example
116
+ # validate_value { |v| v == "John" }
117
+ #
118
+ def validate_value &block
119
+ @check_value_block = block
120
+ self
121
+ end
122
+
123
+
124
+ # Check the default value.
125
+ #
126
+ # @param value The value of this attribute to validate.
127
+ #
128
+ def trigger_default_directive
129
+ @default_block.call if has_default?
130
+ end
131
+
132
+
133
+ # Check value.
134
+ #
135
+ def trigger_content_directive value
136
+ if @check_value_block
137
+ raise YAS::ValidationError, "Content validation error: #{value}" unless
138
+ @check_value_block.call(value)
139
+ end
140
+ value
141
+ end
142
+
143
+
144
+ # Check type.
145
+ #
146
+ def trigger_type_directive value
147
+ if @type
148
+ # Run auto-conversion first.
149
+ value = trigger_auto_convert_directive(value)
150
+
151
+ msg = "Type mismatch for attribute #{@name}"
152
+ if @type <= YAS::Schema
153
+ value = @type.validate(value)
154
+ elsif @type == TrueClass || @type == FalseClass
155
+ raise YAS::ValidationError, msg unless !!value == value
156
+ else
157
+ raise YAS::ValidationError, msg unless value.is_a?(@type)
158
+ end
159
+ end
160
+
161
+ value
162
+ end
163
+
164
+
165
+ # Auto convert the value
166
+ #
167
+ def trigger_auto_convert_directive value
168
+ if @auto_convert
169
+ if @type == Integer
170
+ value = Integer(value)
171
+ elsif @type == Float
172
+ value = Float(value)
173
+ elsif @type == String
174
+ value = String(value)
175
+ elsif @type == Array
176
+ value = Array(value)
177
+ elsif @type == Time && !value.is_a?(Time)
178
+ value = Time.parse(value)
179
+ elsif @type == TrueClass || @type == FalseClass
180
+ value = value == "1" || value == 1 || value.to_s.downcase == "true" || value == true ? true : false
181
+ end
182
+ end
183
+ value
184
+ end
185
+
186
+
187
+ # Validates attribute, except the required directive.
188
+ # First it executes the {default} directive, then {auto_convert} to type,
189
+ # then {type} validation, then finally the {validate} directive.
190
+ #
191
+ # @return The final value after the validation.
192
+ #
193
+ def validate value
194
+ value = trigger_default_directive if value.nil?
195
+ trigger_content_directive(trigger_type_directive(value))
196
+ end
197
+
198
+ end
199
+ end
@@ -0,0 +1,39 @@
1
+ # Migrate the value of a key
2
+ #
3
+
4
+ class YAS::MigrateExt
5
+
6
+ module ClassMethods
7
+
8
+ def migrate key, &block
9
+ migrate_keys[key] = block
10
+ end
11
+
12
+
13
+ def migrate_keys
14
+ @migrate_keys ||= {}
15
+ end
16
+
17
+ end
18
+
19
+
20
+ def self.when_used schema
21
+ schema.extend ClassMethods
22
+ end
23
+
24
+
25
+ def self.when_schema_inherited superschema, subschema
26
+ superschema.migrate_keys.each do |key, pr|
27
+ subschema.migrate_keys[key] = pr
28
+ end
29
+ end
30
+
31
+
32
+ def self.apply schema, hash
33
+ schema.migrate_keys.each do |key, pr|
34
+ hash.has_key?(key) and
35
+ hash[key] = pr.call(hash[key])
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,43 @@
1
+ # Rename keys from one to another
2
+ #
3
+ # Usage:
4
+ #
5
+ # To rename `fname` to `first_name`, and `lname` to `last_name`
6
+ # rename :fname => :first_name, :lname => :last_name
7
+ #
8
+
9
+ class YAS::RenameExt
10
+
11
+ module ClassMethods
12
+ def rename map
13
+ smap = YAS.symbolize(map)
14
+ rename_keys.merge!(smap)
15
+ end
16
+
17
+ def rename_keys
18
+ @rename_keys ||= {}
19
+ end
20
+ end
21
+
22
+
23
+ def self.when_used schema
24
+ schema.extend ClassMethods
25
+ end
26
+
27
+
28
+ def self.when_schema_inherited superschema, subschema
29
+ superschema.rename_keys.each do |from, value|
30
+ subschema.rename_keys[key] = value
31
+ end
32
+ end
33
+
34
+
35
+ def self.apply schema, hash
36
+ schema.rename_keys.each do |from, to|
37
+ hash.has_key?(from) and
38
+ hash[to] = hash[from] and
39
+ hash.delete(from)
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,43 @@
1
+ # Whitelist hash to only contain a set of keys
2
+ #
3
+
4
+ class YAS::WhitelistExt
5
+
6
+ module ClassMethods
7
+ def whitelist *keys
8
+ keys = Array(keys)
9
+ keys.flatten!
10
+ keys.uniq!
11
+ keys.compact!
12
+ keys.each do |k| whitelist_keys << k; end
13
+ whitelist_keys.flatten!
14
+ whitelist_keys.uniq!
15
+ whitelist_keys.compact!
16
+ end
17
+
18
+ def whitelist_keys
19
+ @whitelist_keys ||= []
20
+ end
21
+ end
22
+
23
+
24
+ def self.when_used schema
25
+ schema.extend ClassMethods
26
+ end
27
+
28
+
29
+ def self.when_schema_inherited superschema, subschema
30
+ superschema.whitelist_keys.each do |key|
31
+ subschema.whitelist_keys << key
32
+ end
33
+ end
34
+
35
+
36
+ def self.apply schema, hash
37
+ hash.delete_if do |k, v|
38
+ !schema.whitelist_keys.include?(k)
39
+ end unless schema.whitelist_keys.empty?
40
+ end
41
+
42
+
43
+ end
data/lib/yas/hash.rb ADDED
@@ -0,0 +1,23 @@
1
+ class Hash
2
+
3
+ def validate schema
4
+ copy = Marshal.load(Marshal.dump(self))
5
+ schema.validate(copy) if schema.respond_to?(:validate)
6
+ end
7
+
8
+
9
+ def validate! schema
10
+ schema.validate(self) if schema.respond_to?(:validate)
11
+ end
12
+
13
+
14
+ def slice *keys
15
+ keys.flatten!
16
+ data = keys.inject({}) do |memo, key|
17
+ memo[key] = self[key] if self[key]
18
+ memo
19
+ end
20
+ data
21
+ end
22
+
23
+ end
data/lib/yas/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ module YAS
2
+
3
+ def self.symbolize hash
4
+ hash.inject({}) do |memo,(k,v)|
5
+ memo[k.to_sym] = v
6
+ memo
7
+ end
8
+ end
9
+
10
+ end
data/lib/yas/schema.rb ADDED
@@ -0,0 +1,46 @@
1
+ class YAS::SchemaBase
2
+
3
+ def self.use ext
4
+ raise YAS::ExtensionError, "Duplicate Extension" if exts.any? { |e| e == ext }
5
+ raise YAS::ExtensionError, "Wrong Extension Format" unless ext.respond_to?(:apply) && ext.respond_to?(:when_used)
6
+ exts << ext
7
+ ext.when_used(self)
8
+ end
9
+
10
+
11
+ def self.exts
12
+ @exts ||= []
13
+ end
14
+
15
+
16
+ def self.validate hash
17
+ exts.each do |ext|
18
+ ext.apply(self, hash)
19
+ end
20
+ hash
21
+ end
22
+
23
+
24
+ def self.inspect
25
+ exts.inspect
26
+ end
27
+
28
+
29
+ # Inherited hook to inherit all extensions.
30
+ def self.inherited subclass
31
+ exts.each do |ext|
32
+ subclass.use(ext)
33
+ ext.when_schema_inherited(self, subclass) if ext.respond_to?(:when_schema_inherited)
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ class YAS::Schema < YAS::SchemaBase
40
+
41
+ use YAS::RenameExt
42
+ use YAS::WhitelistExt
43
+ use YAS::MigrateExt
44
+ use YAS::AttributeExt
45
+
46
+ end
@@ -0,0 +1,5 @@
1
+ module YAS
2
+ GEM_NAME = "yas"
3
+ NAME = "YAS"
4
+ VERSION = "0.1.0"
5
+ end
data/lib/yas.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'securerandom'
2
+ require 'json'
3
+ require 'time'
4
+
5
+ require 'yas/version'
6
+ require 'yas/errors'
7
+ require 'yas/helper'
8
+
9
+ require 'yas/ext/rename'
10
+ require 'yas/ext/attribute'
11
+ require 'yas/ext/migrate'
12
+ require 'yas/ext/whitelist'
13
+
14
+ require 'yas/schema'
15
+ require 'yas/hash'
@@ -0,0 +1,200 @@
1
+ require './test/helper.rb'
2
+
3
+ class TestAttribute < Minitest::Test
4
+
5
+ Attribute = YAS::AttributeExt::Attribute
6
+
7
+ def test_required
8
+ attr = Attribute.new(:batman).required
9
+ assert_equal true, attr.required?
10
+ end
11
+
12
+
13
+ def test_type
14
+ attr = Attribute.new(:batman).type(String)
15
+ assert_equal "hello", attr.validate("hello")
16
+ assert_raises YAS::ValidationError do
17
+ attr.validate(1)
18
+ end
19
+ end
20
+
21
+
22
+ def test_auto_convert_integer
23
+ attr = Attribute.new(:batman).type(Integer).auto_convert
24
+ assert_equal 1000, attr.validate(1000)
25
+ assert_equal 1000, attr.validate("1000")
26
+ end
27
+
28
+
29
+ def test_auto_convert_float
30
+ attr = Attribute.new(:batman).type(Float).auto_convert
31
+ assert_equal 1000.01, attr.validate(1000.01)
32
+ assert_equal 1000.01, attr.validate("1000.01")
33
+ end
34
+
35
+
36
+ def test_auto_convert_string
37
+ attr = Attribute.new(:batman).type(String).auto_convert
38
+ assert_equal "hello", attr.validate("hello")
39
+ assert_equal "1", attr.validate(1)
40
+ end
41
+
42
+
43
+ def test_auto_convert_array
44
+ attr = Attribute.new(:batman).type(Array).auto_convert
45
+ assert_equal ["hello"], attr.validate(["hello"])
46
+ assert_equal [1], attr.validate(1)
47
+ end
48
+
49
+
50
+ def test_auto_convert_time
51
+ attr = Attribute.new(:batman).type(Time).auto_convert
52
+ time = attr.validate("2014/7/14")
53
+ assert time.is_a?(Time)
54
+ assert_equal 2014, time.year
55
+ assert_equal 7, time.month
56
+ assert_equal 14, time.day
57
+
58
+ time = attr.validate(Time.now.utc)
59
+ assert time
60
+ end
61
+
62
+
63
+ def test_auto_convert_boolean
64
+ attr = Attribute.new(:batman).type(TrueClass).auto_convert
65
+ assert_equal false, attr.validate("false")
66
+ assert_equal false, attr.validate("123")
67
+ assert_equal true, attr.validate(1)
68
+ assert_equal true, attr.validate("true")
69
+ assert_equal true, attr.validate("1")
70
+ assert_equal false, attr.validate(0)
71
+ assert_equal false, attr.validate(nil)
72
+ end
73
+
74
+
75
+ def test_default
76
+ attr = Attribute.new(:batman).default { "John" }
77
+ assert_equal "John", attr.validate(nil)
78
+ end
79
+
80
+
81
+ def test_has_default
82
+ attr = Attribute.new(:batman).default { "John" }
83
+ assert_equal true, attr.has_default?
84
+
85
+ no_default_attr = Attribute.new(:batman)
86
+ assert_equal false, no_default_attr.has_default?
87
+ end
88
+
89
+
90
+ def test_content
91
+ attr = Attribute.new(:batman).validate_value { |v| v == "John" }
92
+ assert_raises YAS::ValidationError do
93
+ attr.validate("Jim")
94
+ end
95
+ attr.validate("John")
96
+ end
97
+
98
+
99
+ def test_all
100
+ attr = Attribute.new(:batman)
101
+ .required
102
+ .type(Integer)
103
+ .default { 0 }
104
+ .validate_value { |v| v >= 0 }
105
+
106
+ assert_equal true, attr.required?
107
+ assert_equal 0, attr.validate(nil)
108
+ assert_equal 100, attr.validate(100)
109
+ assert_raises YAS::ValidationError do
110
+ attr.validate(-100)
111
+ end
112
+ end
113
+
114
+
115
+ def test_validate_maintain_value_if_type_not_specified
116
+ attr = Attribute.new(:batman)
117
+ [true, false, :symbol, 1, 0, -1, 10.0, "string", 1293.1, 0x90, Time.now, nil].each do |v|
118
+ assert_equal v, attr.validate(v)
119
+ end
120
+ end
121
+
122
+ end
123
+
124
+
125
+ class AttributeSchema < YAS::Schema
126
+
127
+ key :name do
128
+ required
129
+ type String
130
+ auto_convert
131
+ default { "joe" }
132
+ validate_value { |v| v.length < 10 }
133
+ end
134
+
135
+ key :number do
136
+ required
137
+ type Integer
138
+ auto_convert
139
+ end
140
+
141
+ end
142
+
143
+
144
+ class NestedAttributeSchema < YAS::Schema
145
+
146
+ key :personal_info do
147
+ required
148
+ type AttributeSchema
149
+ end
150
+
151
+ end
152
+
153
+
154
+ class TestAttributeExt < Minitest::Test
155
+
156
+ def test_attribute_ext
157
+ hash = {
158
+ name: "someone",
159
+ number: 10,
160
+ }
161
+ hash.validate! AttributeSchema
162
+ assert_equal "someone", hash[:name]
163
+ end
164
+
165
+
166
+ def test_attribute_ext_validate_value
167
+ hash = {
168
+ name: "someone with long name",
169
+ number: 99,
170
+ }
171
+ assert_raises YAS::ValidationError do
172
+ hash.validate! AttributeSchema
173
+ end
174
+ end
175
+
176
+
177
+ def test_attribute_ext_autoconvert_and_nil_attribute
178
+ hash = {
179
+ name: nil,
180
+ number: "10"
181
+ }
182
+ hash.validate! AttributeSchema
183
+ assert_equal 10, hash[:number]
184
+ assert_equal "joe", hash[:name]
185
+ end
186
+
187
+
188
+ def test_nested_attribute_schema
189
+ hash = {
190
+ personal_info: {
191
+ name: nil,
192
+ number: "10"
193
+ }
194
+ }
195
+ hash.validate! NestedAttributeSchema
196
+ assert_equal 10, hash[:personal_info][:number]
197
+ assert_equal "joe", hash[:personal_info][:name]
198
+ end
199
+
200
+ end
@@ -0,0 +1,22 @@
1
+ require './test/helper.rb'
2
+
3
+
4
+ class MigrateSchema < YAS::Schema
5
+ migrate :names do |v|
6
+ v = Array(v) if !v.is_a?(Array)
7
+ v
8
+ end
9
+ end
10
+
11
+
12
+ class TestMigrateExt < Minitest::Test
13
+
14
+ def test_migrate_ext
15
+ hash = {
16
+ names: "john"
17
+ }
18
+ hash.validate! MigrateSchema
19
+ assert_equal ["john"], hash[:names]
20
+ end
21
+
22
+ end
@@ -0,0 +1,22 @@
1
+ require './test/helper.rb'
2
+
3
+ class RenameSchema < YAS::Schema
4
+ rename :addr => :address
5
+ end
6
+
7
+
8
+ class TestRenameExt < Minitest::Test
9
+
10
+ def test_rename_ext
11
+ hash = {
12
+ addr: "Some address",
13
+ untouched: "Nothing"
14
+ }
15
+ hash.validate! RenameSchema
16
+ assert_equal "Some address", hash[:address]
17
+ assert_equal "Nothing", hash[:untouched]
18
+ assert_nil hash[:addr]
19
+ assert_equal 2, hash.length
20
+ end
21
+
22
+ end
@@ -0,0 +1,25 @@
1
+ require './test/helper.rb'
2
+
3
+
4
+ class WhitelistSchema < YAS::Schema
5
+ whitelist :first_name, :last_name, :address
6
+ end
7
+
8
+
9
+ class TestWhitelistExt < Minitest::Test
10
+
11
+ def test_whitelist_ext
12
+ hash = {
13
+ first_name: "john",
14
+ last_name: "doe",
15
+ address: "123 Main St",
16
+ invalid: "will get removed",
17
+ }
18
+ hash.validate! WhitelistSchema
19
+ assert_equal "john", hash[:first_name]
20
+ assert_equal "doe", hash[:last_name]
21
+ assert_equal "123 Main St", hash[:address]
22
+ assert_nil hash[:invalid]
23
+ end
24
+
25
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,6 @@
1
+ require './lib/yas.rb'
2
+
3
+ require 'minitest/autorun'
4
+ require 'minitest/unit'
5
+ require 'mocha/mini_test'
6
+
@@ -0,0 +1,97 @@
1
+ require './test/helper.rb'
2
+
3
+
4
+ class MigrateSchema < YAS::Schema
5
+ migrate :names do |v|
6
+ v = Array(v) if !v.is_a?(Array)
7
+ v
8
+ end
9
+ end
10
+
11
+
12
+ class InheritedSchema < MigrateSchema
13
+ rename :book => :books
14
+ end
15
+
16
+
17
+ class ComplexSchema < MigrateSchema
18
+
19
+ whitelist :name, :contact_name, :contact_email, :redirect_uris, :active
20
+
21
+ attribute :name do
22
+ required
23
+ type String
24
+ end
25
+
26
+ attribute :contact_name do
27
+ required
28
+ type String
29
+ end
30
+
31
+ rename :email => :contact_email
32
+ attribute :contact_email do
33
+ required
34
+ type String
35
+ end
36
+
37
+ rename :redirect_uri => :redirect_uris
38
+ attribute :redirect_uris do
39
+ required
40
+ type Array
41
+ auto_convert
42
+ end
43
+ migrate :redirect_uris do |v|
44
+ v = Array(v) if !v.is_a?(Array)
45
+ v
46
+ end
47
+
48
+ attribute :active do
49
+ required
50
+ type TrueClass
51
+ auto_convert
52
+ default { true }
53
+ end
54
+
55
+ end
56
+
57
+
58
+ class TestSchema < Minitest::Test
59
+
60
+ def test_validate_not_bang_does_not_overwrite_original
61
+ hash = {
62
+ names: "john",
63
+ }
64
+ result = hash.validate MigrateSchema
65
+ assert_equal ["john"], result[:names]
66
+ assert_equal "john", hash[:names]
67
+ end
68
+
69
+ def test_inherited_schema_should_inherit_extensions
70
+ hash = {
71
+ names: "john",
72
+ book: "Dolly",
73
+ }
74
+ hash.validate! InheritedSchema
75
+ assert_equal ["john"], hash[:names]
76
+ assert_equal "Dolly", hash[:books]
77
+ assert_nil hash[:book]
78
+ end
79
+
80
+ def test_complex_schema
81
+ hash = {
82
+ name: "john",
83
+ contact_name: "someone else",
84
+ email: "jdoe@example.com",
85
+ redirect_uri: "jdoe.com",
86
+ active: 1,
87
+ }
88
+ hash.validate! ComplexSchema
89
+ assert_equal "john", hash[:name]
90
+ assert_equal "someone else", hash[:contact_name]
91
+ assert_equal "jdoe@example.com", hash[:contact_email]
92
+ assert_nil hash[:email]
93
+ assert_equal ["jdoe.com"], hash[:redirect_uris]
94
+ assert_equal true, hash[:active]
95
+ end
96
+
97
+ end
data/yas.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'yas/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "#{YAS::GEM_NAME}"
6
+ s.version = YAS::VERSION
7
+ s.authors = ["Albert Tedja"]
8
+ s.email = "nicho_tedja@yahoo.com"
9
+ s.homepage = "https://github.com/atedja/yahs"
10
+ s.summary = "Yet Another Schema for Ruby."
11
+ s.description = "#{YAS::NAME} is a Ruby hash schema and validator."
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
15
+ s.require_paths = ["lib"]
16
+
17
+ s.required_ruby_version = '~> 2.0'
18
+ s.add_development_dependency 'minitest', '~> 5.3'
19
+ s.add_development_dependency 'mocha', '~> 1.1'
20
+ s.add_development_dependency 'rake', '~> 10.3'
21
+
22
+ s.license = "Apache"
23
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yas
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Albert Tedja
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mocha
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.3'
55
+ description: YAS is a Ruby hash schema and validator.
56
+ email: nicho_tedja@yahoo.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - README.markdown
63
+ - Rakefile
64
+ - lib/yas.rb
65
+ - lib/yas/errors.rb
66
+ - lib/yas/ext/attribute.rb
67
+ - lib/yas/ext/migrate.rb
68
+ - lib/yas/ext/rename.rb
69
+ - lib/yas/ext/whitelist.rb
70
+ - lib/yas/hash.rb
71
+ - lib/yas/helper.rb
72
+ - lib/yas/schema.rb
73
+ - lib/yas/version.rb
74
+ - test/ext/test_attribute.rb
75
+ - test/ext/test_migrate.rb
76
+ - test/ext/test_rename.rb
77
+ - test/ext/test_whitelist.rb
78
+ - test/helper.rb
79
+ - test/test_schema.rb
80
+ - yas.gemspec
81
+ homepage: https://github.com/atedja/yahs
82
+ licenses:
83
+ - Apache
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '2.0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.4.8
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Yet Another Schema for Ruby.
105
+ test_files: []
106
+ has_rdoc: