typical 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: d39962302fd2b80a007d4c6212e8251144e7817f
4
+ data.tar.gz: 595b2bc1838b0b136f4e34b4cd99eb912727e5b5
5
+ SHA512:
6
+ metadata.gz: 146cd162336ae7042a4d32019cdbaf7c616f4daf2f8d80989cd271f9d17fecdbe64a34633ee1e038d3ede8f55fe3ea25594a386191c01f5c8d92b4af766bebb5
7
+ data.tar.gz: 1db4dc5f3078c55e609a67591831e81f3397bd6fa62e8d5141cab24dc05d4c3e69e787370e4191c678cac006be371f48d3cadccf8af15ee5018ccc3f9de4dd69
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.14.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in typical.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,41 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ typical (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ansi (1.5.0)
10
+ builder (3.2.3)
11
+ minitest (5.10.2)
12
+ minitest-around (0.4.0)
13
+ minitest (~> 5.0)
14
+ minitest-focus (1.1.2)
15
+ minitest (>= 4, < 6)
16
+ minitest-reporters (1.1.14)
17
+ ansi
18
+ builder
19
+ minitest (>= 5.0)
20
+ ruby-progressbar
21
+ minitest-sprint (1.2.0)
22
+ path_expander (~> 1.0)
23
+ path_expander (1.0.2)
24
+ rake (10.5.0)
25
+ ruby-progressbar (1.8.1)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ bundler (~> 1.14)
32
+ minitest (~> 5.0)
33
+ minitest-around (~> 0.4)
34
+ minitest-focus
35
+ minitest-reporters
36
+ minitest-sprint
37
+ rake (~> 10.0)
38
+ typical!
39
+
40
+ BUNDLED WITH
41
+ 1.14.6
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Eloy Durán <eloy.de.enige@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # Typical
2
+
3
+ This library provides a DSL to describe the types of your data and ways to validate them.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "typical"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install typical
20
+
21
+ ## Usage
22
+
23
+ ### DSL
24
+
25
+ To specify type information, you can use the `Typical::DSL` module.
26
+
27
+ ```ruby
28
+ require "typical/dsl"
29
+ include Typical::DSL
30
+ ```
31
+
32
+ The bang methods are used to define types.
33
+
34
+ ```ruby
35
+ String! # => #<Type:String>
36
+ ```
37
+
38
+ You can allow multiple types by creating a union of them.
39
+
40
+ ```ruby
41
+ String! | Integer! # => #<Type:Union [#<Type:String>, #<Type:Integer>]>
42
+ ```
43
+
44
+ Sometimes a field can also be null.
45
+
46
+ ```ruby
47
+ String! | Integer! | null # => #<Type:Union [#<Type:String>, , #<Type:Integer>, #<Type:NilClass>]>
48
+ ```
49
+
50
+ If you’re defining a single type, but nullable, use the question mark methods instead.
51
+
52
+ ```ruby
53
+ String? # => #<Type:Union [#<Type:String>, #<Type:NilClass>]>
54
+ ```
55
+
56
+ You can have collections too, you use them like you normally would.
57
+
58
+ ```ruby
59
+ Set!(String!, Integer!) # => #<Type:Set [#<Type:Union [#<Type:String>, #<Type:Integer>]>]>
60
+ Array!(String!, Integer!) # => #<Type:Array [#<Type:Union [#<Type:String>, #<Type:Integer>]>]>
61
+ Hash!(String! => Integer!) # => #<Type:Hash { [#<Type:Union [#<Type:String>]>] => [#<Type:Union [#<Type:Integer>]>] }>
62
+ ```
63
+
64
+ ### Validation
65
+
66
+ _NOTE: This is not yet implemented._
67
+
68
+ ```ruby
69
+ typing = Array!(String!)
70
+ typing.valid?("string") # => false
71
+ typing.valid?([nil]) # => false
72
+ typing.valid?([]) # => true
73
+ typing.valid?(["string"]) # => true
74
+ ```
75
+
76
+ ### Mongoid
77
+
78
+ _NOTE: This is not yet implemented._
79
+
80
+ This Mongoid integration allows you to both reflect on the data types in your database and validate incoming data.
81
+
82
+ ```ruby
83
+ class Artist
84
+ include Mongoid::Document
85
+ include Typical::Mongoid
86
+
87
+ field :name, type: String?
88
+ field :image_versions, type: Array!(Symbol!)
89
+ field :image_urls, type: Hash!(String! => String!)
90
+ end
91
+ ```
92
+
93
+ ## Development
94
+
95
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
96
+
97
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
98
+
99
+ ## Contributing
100
+
101
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alloy/typical.
102
+
103
+ ## License
104
+
105
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
106
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs << "spec"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["spec/**/*_spec.rb"]
8
+ end
9
+
10
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "typical"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,63 @@
1
+ require "typical/type"
2
+
3
+ module Typical
4
+ module DSL
5
+ def self.define_scalar_type(mod, name = nil)
6
+ name ||= mod.name
7
+ define_method("#{name}!") { Type.new(mod) }
8
+ define_method("#{name}?") { Type.new(mod) | null }
9
+ end
10
+
11
+ BUILTIN_SCALAR_TYPES = [
12
+ Integer,
13
+ Float,
14
+ Object,
15
+ Range,
16
+ Regexp,
17
+ String,
18
+ Symbol,
19
+ Time,
20
+ ].freeze
21
+
22
+ BUILTIN_SCALAR_TYPES.each do |klass|
23
+ define_scalar_type(klass)
24
+ end
25
+
26
+ def null
27
+ Type.new(NilClass)
28
+ end
29
+
30
+ def Hash!(types = {})
31
+ Type::Hash.new(types)
32
+ end
33
+
34
+ def Hash?(types = {})
35
+ Hash!(types) | null
36
+ end
37
+
38
+ def Set!(*types)
39
+ Type::Set.new(*types)
40
+ end
41
+
42
+ # TODO: It actually appears that mongo/mongoid does not return `null` for set fields.
43
+ def Set?(*types)
44
+ Set!(*types) | null
45
+ end
46
+
47
+ def Array!(*types)
48
+ Type::Array.new(types)
49
+ end
50
+
51
+ def Array?(*types)
52
+ Array!(*types) | null
53
+ end
54
+
55
+ def Reference!(reference)
56
+ Type::Reference.new(reference)
57
+ end
58
+
59
+ def Reference?(reference)
60
+ Reference!(reference) | null
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,123 @@
1
+ require "typical/type"
2
+ require "typical/type/union"
3
+
4
+ module Typical
5
+ class Type
6
+ class List < Type
7
+ attr_reader :storage
8
+
9
+ def initialize(*objects)
10
+ @storage = new_storage
11
+ load_from_objects(objects)
12
+ end
13
+
14
+ def normalize
15
+ self.class.new.tap { |copy| copy.values = values.normalize(false) }
16
+ end
17
+
18
+ def values
19
+ @storage[:values]
20
+ end
21
+
22
+ def values=(values)
23
+ @storage[:values] = values
24
+ end
25
+
26
+ def empty?
27
+ values.empty?
28
+ end
29
+
30
+ def ==(other)
31
+ other.is_a?(self.class) && values == other.values
32
+ end
33
+
34
+ def eql?(other)
35
+ super && @storage == other.storage
36
+ end
37
+
38
+ def hash
39
+ [super, @storage].hash
40
+ end
41
+
42
+ def inspect
43
+ "#<Type:#{type} [#{values.inspect}]>"
44
+ end
45
+
46
+
47
+ private
48
+
49
+ def new_storage
50
+ { values: Union.new }
51
+ end
52
+
53
+ def load_from_objects(objects)
54
+ objects.each do |object|
55
+ if object.is_a?(type)
56
+ load_from_list_object(object)
57
+ else
58
+ load_from_object(object)
59
+ end
60
+ end
61
+ end
62
+
63
+ def load_from_list_object(list)
64
+ list.each { |object| load_from_object(object) }
65
+ end
66
+
67
+ def load_from_object(object, storage_key = :values)
68
+ @storage[storage_key].types << Type.of(object)
69
+ end
70
+ end
71
+
72
+ class Array < List
73
+ def type
74
+ ::Array
75
+ end
76
+ end
77
+
78
+ class Set < List
79
+ def type
80
+ ::Set
81
+ end
82
+ end
83
+
84
+ class Hash < List
85
+ def type
86
+ ::Hash
87
+ end
88
+
89
+ def normalize
90
+ super.tap { |copy| copy.keys = keys.normalize(false) }
91
+ end
92
+
93
+ def keys
94
+ @storage[:keys]
95
+ end
96
+
97
+ def keys=(keys)
98
+ @storage[:keys] = keys
99
+ end
100
+
101
+ def inspect
102
+ "#<Type:#{type} { [#{keys.inspect}] => [#{values.inspect}] }>"
103
+ end
104
+
105
+ def ==(other)
106
+ super && keys == other.keys
107
+ end
108
+
109
+ private
110
+
111
+ def new_storage
112
+ super.merge(keys: Union.new)
113
+ end
114
+
115
+ def load_from_list_object(hash)
116
+ hash.each do |key, value|
117
+ load_from_object(key, :keys)
118
+ load_from_object(value, :values)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,11 @@
1
+ require "typical/type"
2
+
3
+ module Typical
4
+ class Type
5
+ class Reference < Type
6
+ def inspect
7
+ "#<Type:Reference(#{type})>"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,74 @@
1
+ require "typical/type"
2
+
3
+ module Typical
4
+ class Type
5
+ class Union < Type
6
+ attr_reader :types
7
+
8
+ def initialize(types = [])
9
+ raise TypeError, "Requires an array of types" unless types.is_a?(::Array)
10
+ @types = ::Set.new(types.map { |type| Type.of(type) })
11
+ end
12
+
13
+ def prominent_type
14
+ copy = types.dup
15
+ copy.delete_if { |type| type.type == NilClass }
16
+ copy.first if copy.size == 1
17
+ end
18
+
19
+ def empty?
20
+ @types.empty?
21
+ end
22
+
23
+ def ==(other)
24
+ other.is_a?(Union) && @types == other.types
25
+ end
26
+
27
+ def hash
28
+ @types.hash
29
+ end
30
+
31
+ def |(other)
32
+ raise TypeError, "Can only make a union of Type and subclasses of Type" unless other.is_a?(Type)
33
+ Union.new((types + other.types).to_a)
34
+ end
35
+
36
+ def normalize(unwrap_single_type = true)
37
+ normalized = Union.new
38
+ types = self.types.dup
39
+
40
+ arrays = types.select { |type| type.type == ::Array }
41
+ unless arrays.empty?
42
+ types -= arrays
43
+ normalized |= Array.new(arrays.map(&:values).reduce(:|).types.to_a).normalize
44
+ end
45
+
46
+ sets = types.select { |type| type.type == ::Set }
47
+ unless sets.empty?
48
+ types -= sets
49
+ normalized |= Set.new(::Set.new(sets.map(&:values).reduce(:|).types.to_a)).normalize
50
+ end
51
+
52
+ hashes = types.select { |type| type.type == ::Hash }
53
+ unless hashes.empty?
54
+ types -= hashes
55
+ hash = Hash.new
56
+ hash.keys |= hashes.map(&:keys).reduce(:|)
57
+ hash.values |= hashes.map(&:values).reduce(:|)
58
+ normalized |= hash.normalize
59
+ end
60
+
61
+ # Add remainder
62
+ types.each { |type| normalized |= type.normalize }
63
+ # If there’s only 1 type, unwrap it from the union type.
64
+ normalized = normalized.types.first if unwrap_single_type && normalized.types.size == 1
65
+
66
+ normalized
67
+ end
68
+
69
+ def inspect
70
+ "#<Type:Union [#{@types.map(&:inspect).join(", ")}]>"
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,76 @@
1
+ module Typical
2
+ class Type
3
+ def self.of(object)
4
+ case object
5
+ when Type
6
+ object
7
+ when ::Hash
8
+ Hash.new(object)
9
+ when ::Array
10
+ Array.new(object)
11
+ when ::Set
12
+ Set.new(object)
13
+ when Class
14
+ if object == ::Hash
15
+ Hash.new
16
+ elsif object == ::Array
17
+ Array.new
18
+ elsif object == ::Set
19
+ Set.new
20
+ else
21
+ new(object)
22
+ end
23
+ else
24
+ new(object.class)
25
+ end
26
+ end
27
+
28
+ attr_reader :type
29
+
30
+ def initialize(type)
31
+ @type = type
32
+ end
33
+
34
+ # This makes Type and Type::Union duck-typable
35
+ def types
36
+ ::Set.new([self])
37
+ end
38
+
39
+ def ==(other)
40
+ other.is_a?(Type) && type == other.type
41
+ end
42
+
43
+ def eql?(other)
44
+ self == other
45
+ end
46
+
47
+ def hash
48
+ type.hash
49
+ end
50
+
51
+ def |(other)
52
+ raise TypeError, "Can only make a union of Type and subclasses of Type" unless other.is_a?(Type)
53
+ other.is_a?(Union) ? (other | self) : Union.new([self, other])
54
+ end
55
+
56
+ def nullable?
57
+ types.any? { |type| type.type == NilClass }
58
+ end
59
+
60
+ def normalize
61
+ self
62
+ end
63
+
64
+ def prominent_type
65
+ self
66
+ end
67
+
68
+ def inspect
69
+ "#<Type:#{type}>"
70
+ end
71
+ end
72
+ end
73
+
74
+ require "typical/type/list"
75
+ require "typical/type/reference"
76
+ require "typical/type/union"
@@ -0,0 +1,3 @@
1
+ module Typical
2
+ VERSION = "0.1.0"
3
+ end
data/lib/typical.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "typical/type"
2
+ require "typical/version"
3
+
4
+ module Typical
5
+ end
data/typical.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'typical/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "typical"
8
+ spec.version = Typical::VERSION
9
+ spec.authors = ["Eloy Durán"]
10
+ spec.email = ["eloy.de.enige@gmail.com"]
11
+
12
+ spec.summary = "A Ruby library to describe the types of your data and ways to validate them."
13
+ spec.homepage = "https://github.com/alloy/typical"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.14"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "minitest", "~> 5.0"
24
+ spec.add_development_dependency "minitest-around", "~> 0.4"
25
+ spec.add_development_dependency "minitest-reporters"
26
+ spec.add_development_dependency "minitest-sprint"
27
+ spec.add_development_dependency "minitest-focus"
28
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typical
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Eloy Durán
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-around
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-reporters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest-sprint
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest-focus
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description:
112
+ email:
113
+ - eloy.de.enige@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - bin/console
126
+ - bin/setup
127
+ - lib/typical.rb
128
+ - lib/typical/dsl.rb
129
+ - lib/typical/type.rb
130
+ - lib/typical/type/list.rb
131
+ - lib/typical/type/reference.rb
132
+ - lib/typical/type/union.rb
133
+ - lib/typical/version.rb
134
+ - typical.gemspec
135
+ homepage: https://github.com/alloy/typical
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.6.11
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: A Ruby library to describe the types of your data and ways to validate them.
159
+ test_files: []