bhm 0.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 +7 -0
- data/README.md +40 -0
- data/examples/meta.rb +10 -0
- data/examples/team.rb +21 -0
- data/examples/user.rb +21 -0
- data/lib/bhm.rb +5 -0
- data/lib/bhm/errors.rb +90 -0
- data/lib/bhm/scaffold.rb +47 -0
- data/lib/bhm/utils.rb +61 -0
- data/lib/bhm/validation.rb +194 -0
- data/lib/bhm/version.rb +3 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: deba451efeb03dbbbc84340918f311129808c08401b98cdbe9e2b309cae64b3d
|
4
|
+
data.tar.gz: 8aca882d42fedbc4fc01f0317aea620eeadbd6b63034de4e197a5855bd774c42
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9b643a56b5e6689e4013de3a035609b222dc895cd416634be0bf889e15d0aca574cc66ccdd4f8c93fdb98a0590ae7c38142fddcf6a8a01e8dcb3ff0b7da4c71f
|
7
|
+
data.tar.gz: b9c2c24d3e2147eb0fd67534fce82c74675fc1bc639ed939666d88ca4b8faa08ee54a6642fe17c99d0bdef92cad5ccd1659276669534c75e1cb95c75dc9a817d
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Hsah
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/hsah`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'hsah'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install hsah
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
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).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hsah.
|
36
|
+
|
37
|
+
|
38
|
+
## License
|
39
|
+
|
40
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/examples/meta.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Example of a shared schema, `meta`, to be re-used in multiple places
|
2
|
+
require "bhm"
|
3
|
+
|
4
|
+
module Meta
|
5
|
+
include Bhm::Validation
|
6
|
+
validator :created_at, DateTime
|
7
|
+
validator :updated_at, DateTime
|
8
|
+
|
9
|
+
validator :uuid, ->(value) { value.match?(/\A(\{)?([a-fA-F0-9]{4}-?){8}(?(1)\}|)\z/) }
|
10
|
+
end
|
data/examples/team.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Example of validating a team resource, using the validation helpers
|
2
|
+
require "bhm"
|
3
|
+
require "date"
|
4
|
+
require_relative "meta"
|
5
|
+
require_relative "user"
|
6
|
+
|
7
|
+
module Team
|
8
|
+
include Bhm::Validation
|
9
|
+
validator :name, String
|
10
|
+
validator :rank, Integer
|
11
|
+
validator :users, ->(value) { value.is_a?(Array) && value.each { |user_hash| user_hash.extend(User).validate! } }
|
12
|
+
|
13
|
+
module Budget
|
14
|
+
include Bhm::Validation
|
15
|
+
|
16
|
+
validator :amount, Integer
|
17
|
+
validator :meta, ->(value) { value.extend(Meta).validate! }
|
18
|
+
end
|
19
|
+
|
20
|
+
validator :meta, ->(value) { value.extend(Meta).validate! }
|
21
|
+
end
|
data/examples/user.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Example of validating a user resource, using scaffolding
|
2
|
+
require "bhm"
|
3
|
+
require_relative "meta"
|
4
|
+
|
5
|
+
module User
|
6
|
+
@name = String
|
7
|
+
@email = ->(value) { value.is_a?(String) && value.match?(/[^\s]@[^\s]/) }
|
8
|
+
@tos_acceptance = TrueClass
|
9
|
+
module Address
|
10
|
+
@street = String
|
11
|
+
end
|
12
|
+
|
13
|
+
module Profile
|
14
|
+
@introduction = ->(value) { value.is_a?(String) && value.length < 255 }
|
15
|
+
@hobbies = Array
|
16
|
+
end
|
17
|
+
|
18
|
+
@meta = ->(value) { value.extend(Meta).validate! }
|
19
|
+
end
|
20
|
+
|
21
|
+
User.include(Bhm::Scaffold)
|
data/lib/bhm.rb
ADDED
data/lib/bhm/errors.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
module Bhm
|
2
|
+
module Errors
|
3
|
+
module Chainable
|
4
|
+
# Helper for re-raising easily
|
5
|
+
def self.included(klass)
|
6
|
+
# Add new class method, without needing to prepend the class
|
7
|
+
klass.define_singleton_method(:raise!) do |*args, **kwargs|
|
8
|
+
fail new(args[0], **kwargs)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Retrieve the chain of errors up to the most recent included module
|
13
|
+
# Eg.
|
14
|
+
# hash.extend(Document)
|
15
|
+
# error_chain == [Document, Components, Schemas, Primitive]
|
16
|
+
#
|
17
|
+
# hash.extend(Document::Components)
|
18
|
+
# error_chain == [Components, Schemas, Primitive]
|
19
|
+
def error_chain
|
20
|
+
@error_chain ||= -> {
|
21
|
+
out, parent = [self], cause
|
22
|
+
loop do
|
23
|
+
break out if parent.nil?
|
24
|
+
out.push(parent)
|
25
|
+
parent = parent.cause
|
26
|
+
end
|
27
|
+
}.call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Pre-validation check indicates this should not be validated
|
32
|
+
class WontValidate < ArgumentError
|
33
|
+
include Chainable
|
34
|
+
attr_accessor :receiver
|
35
|
+
def initialize(message = nil, receiver:)
|
36
|
+
message ||= "A guard raised; Will not attempt validation for this hash"
|
37
|
+
self.receiver = receiver
|
38
|
+
super(message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Generic error -- the hash could not be fully validated
|
43
|
+
class InvalidHash < KeyError
|
44
|
+
include Chainable
|
45
|
+
def initialize(message = nil, receiver:, key:)
|
46
|
+
message ||= "the hash could not be fully validated"
|
47
|
+
super(message, receiver: receiver, key: key)
|
48
|
+
end
|
49
|
+
|
50
|
+
# From the invalid hash, get a period-joined string of keys leading to the invalid key or value
|
51
|
+
def ref
|
52
|
+
error_chain.map(&:key).join(".")
|
53
|
+
end
|
54
|
+
|
55
|
+
# TODO: Import absolute_ref
|
56
|
+
end
|
57
|
+
|
58
|
+
# The key does not adhere to the asserted key typing
|
59
|
+
class InvalidKeyType < InvalidHash
|
60
|
+
def initialize(message = nil, receiver:, key:, type:)
|
61
|
+
message ||= "all keys must be #{type} (got #{key.inspect})"
|
62
|
+
super(message, receiver: receiver, key: key)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# The key does not adhere to the asserted key casing
|
67
|
+
class InvalidKeyCasing < InvalidHash
|
68
|
+
def initialize(message = nil, receiver:, key:, casing:)
|
69
|
+
message ||= "the key #{key.inspect} is not in #{casing} casing"
|
70
|
+
super(message, receiver: receiver, key: key)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# A required value was not found
|
75
|
+
class MissingKey < InvalidHash
|
76
|
+
def initialize(message = nil, receiver:, key:)
|
77
|
+
message ||= "could not find key: #{key.inspect}"
|
78
|
+
super(message, receiver: receiver, key: key)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# The value was found, but calling `validate!` on it raised a validation error
|
83
|
+
class InvalidValue < InvalidHash
|
84
|
+
def initialize(message = nil, receiver:, key:)
|
85
|
+
message ||= "a value exists for key #{key.inspect} -- but it did not pass validation"
|
86
|
+
super(message, receiver: receiver, key: key)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/bhm/scaffold.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative "utils"
|
2
|
+
require_relative "validation"
|
3
|
+
|
4
|
+
module Bhm
|
5
|
+
# Quick way to start including hash validation. May be the only module some projects need :)
|
6
|
+
module Scaffold
|
7
|
+
# Upon being included do the following:
|
8
|
+
# - define any validators based on the declared instance_variables
|
9
|
+
# (then)
|
10
|
+
# - fetch all declared modules
|
11
|
+
## And recursively do the following:
|
12
|
+
## - extend it with Bhm::Validation
|
13
|
+
## - define a new validator, using the module name as a key
|
14
|
+
## (a nested module assumes it's a nested hash)
|
15
|
+
#### @mod_name = ->(hash) { hash.extend(ModName).validate! }
|
16
|
+
def self.included(klass)
|
17
|
+
# Include the validation suite in self
|
18
|
+
klass.include(Validation)
|
19
|
+
|
20
|
+
# Find all modules (we are assuming these are hashes)
|
21
|
+
klass.constants.each do |sym|
|
22
|
+
const = const_get([klass, sym].join("::"))
|
23
|
+
next unless const.is_a?(Module)
|
24
|
+
|
25
|
+
# Then, define the validator for the current class (calls validate! on the hash)
|
26
|
+
# default_key_case may return `nil` if no global config is set.
|
27
|
+
casing_transform = klass.default_key_case || :lower_snake
|
28
|
+
key = Utils.transform_module_casing(sym, casing_transform, klass.default_key_type)
|
29
|
+
|
30
|
+
klass.validator key, ->(hash) { hash.extend(const).validate! }
|
31
|
+
|
32
|
+
# Lastly, recursively include the scaffolding suite in these child modules
|
33
|
+
const.include(Scaffold)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Usage:
|
40
|
+
# 1. Define a group of nested modules:
|
41
|
+
# module Apex
|
42
|
+
# module Hash1
|
43
|
+
# module NestedHash
|
44
|
+
# # IF this nested hash is the bottommost "leaf", we will not traverse any further.
|
45
|
+
# # Defining instance variables is still respected
|
46
|
+
# module Hash2
|
47
|
+
# module NestedHash
|
data/lib/bhm/utils.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Bhm
|
2
|
+
module Utils
|
3
|
+
module_function
|
4
|
+
|
5
|
+
# Transform a stringified module to an accessible hash key
|
6
|
+
# Assume we want symbols by default
|
7
|
+
def transform_module_casing(module_name, key_casing, key_type)
|
8
|
+
transformed_module = case key_casing
|
9
|
+
when :lower_snake
|
10
|
+
module_name.to_s.gsub(/[A-Z]/) { |mtch| "_" + mtch.downcase }.sub(/^_/, "")
|
11
|
+
when :lowerCamel
|
12
|
+
module_name.to_s.sub(/^./) { |first_char| first_char.downcase }
|
13
|
+
when :UpperCamel
|
14
|
+
module_name.to_s
|
15
|
+
when :SCREAMING_SNAKE
|
16
|
+
module_name.to_s.gsub(/[A-Z]/) { |mtch| "_" + mtch }.upcase.sub(/^_/, "")
|
17
|
+
else
|
18
|
+
fail ArgumentError, "invalid casing provided: #{key_casing.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Coerce into symbols if key_type was explicitly passed as `nil`
|
22
|
+
key_type ||= :symbols
|
23
|
+
transformed_module = transformed_module.to_sym if key_type == :symbols
|
24
|
+
transformed_module
|
25
|
+
end
|
26
|
+
|
27
|
+
# Take a hash which includes Bhm::Validation & traverse upward nested module which also includes Validation
|
28
|
+
def traverse_ancestors(hash)
|
29
|
+
all = hash.singleton_class.included_modules.select { |mod| mod.include? Validation }
|
30
|
+
current = all.first
|
31
|
+
traversed_ancestors = []
|
32
|
+
|
33
|
+
while current.include?(Validation)
|
34
|
+
as_ary = current.to_s.split("::")
|
35
|
+
# Truncating the final ::(string), then rejoin
|
36
|
+
|
37
|
+
# Now that we have the module in question, transform the case using the module's method, if it has it defined
|
38
|
+
accessed_key = as_ary[-1]
|
39
|
+
|
40
|
+
# HACK: make an instance which extends the current module to use its #default_key values
|
41
|
+
transformed_key = -> do
|
42
|
+
hack = {}.extend(current)
|
43
|
+
key_casing = hack.default_key_case
|
44
|
+
key_type = hack.default_key_type
|
45
|
+
|
46
|
+
transform_module_casing(accessed_key, key_casing, key_type)
|
47
|
+
end.call
|
48
|
+
|
49
|
+
traversed_ancestors << transformed_key
|
50
|
+
|
51
|
+
last = current
|
52
|
+
current = Object.const_get(as_ary[0, (as_ary.length - 1)].join("::"))
|
53
|
+
end
|
54
|
+
|
55
|
+
# Array
|
56
|
+
# idx 0 is an array of the module names as formatted strings
|
57
|
+
# idx 1 is the apex, highest "entry" module
|
58
|
+
[traversed_ancestors, last]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require_relative "errors"
|
2
|
+
require_relative "utils"
|
3
|
+
|
4
|
+
module Bhm
|
5
|
+
# The meat of the library
|
6
|
+
module Validation
|
7
|
+
def self.included(receiver)
|
8
|
+
# NOTE: Methods **MUST** be in the included block -- otherwise we pollute the module constants with
|
9
|
+
# any "initializer" module we include/extend
|
10
|
+
receiver.singleton_class.class_eval do
|
11
|
+
def config(**cfg)
|
12
|
+
pending_case, pending_keys = cfg.values_at(:default_key_case, :default_key_type)
|
13
|
+
|
14
|
+
case_options = [:lower_snake, :lowerCamel, :UpperCamel, :SCREAMING_SNAKE, nil]
|
15
|
+
fail ArgumentError, "casing must be one of #{case_options.inspect}" unless case_options.include? pending_case
|
16
|
+
@___default_key_case = pending_case
|
17
|
+
|
18
|
+
key_options = [:symbols, :strings, nil]
|
19
|
+
fail ArgumentError, "keys must be one of #{key_options.inspect}" unless key_options.include? pending_keys
|
20
|
+
@___default_key_type = pending_keys
|
21
|
+
end
|
22
|
+
|
23
|
+
# Concise API for setting both case assertion & key conformity simultaneously
|
24
|
+
def keys(arg)
|
25
|
+
key_option = arg.is_a?(String) ? :strings : :symbols
|
26
|
+
config(
|
27
|
+
default_key_type: key_option,
|
28
|
+
default_key_case: arg.to_sym
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def default_key_case
|
33
|
+
# @___default_key_case ||= TODO_GLOBAL_CONFIG
|
34
|
+
@___default_key_case
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_key_type
|
38
|
+
# @___default_key_type ||= TODO_GLOBAL_CONFIG
|
39
|
+
@___default_key_type
|
40
|
+
end
|
41
|
+
|
42
|
+
# TODO: `nullable` method
|
43
|
+
|
44
|
+
def guard(handler)
|
45
|
+
guards << handler
|
46
|
+
end
|
47
|
+
|
48
|
+
def guards
|
49
|
+
@___guards ||= []
|
50
|
+
end
|
51
|
+
|
52
|
+
#### 4 ways to define a validator:
|
53
|
+
## Explicit key+proc:
|
54
|
+
# validator "KEY", ->(){}
|
55
|
+
# @KEY = "KEY", ->(){}
|
56
|
+
#
|
57
|
+
## Explicit key+typecheck
|
58
|
+
# validator "KEY", String
|
59
|
+
# @KEY = "KEY", String
|
60
|
+
#
|
61
|
+
## Implicit proc
|
62
|
+
# @___default_key_type = :strings
|
63
|
+
# @KEY = ->(){}
|
64
|
+
#
|
65
|
+
## Implicit typecheck
|
66
|
+
# @___default_key_type = :strings
|
67
|
+
# @KEY = String
|
68
|
+
def validators
|
69
|
+
instance_variables.each_with_object({}) do |ivar, out|
|
70
|
+
# Skip our internals
|
71
|
+
next if ivar.to_s.start_with? "@___"
|
72
|
+
|
73
|
+
arg = instance_variable_get(ivar)
|
74
|
+
final_key, ambiguous_arg = case arg
|
75
|
+
when Array
|
76
|
+
# Assume the array idx0 is the key, idx1 is the handler or a Ruby class
|
77
|
+
arg.slice(0, 2)
|
78
|
+
else
|
79
|
+
# Assume some implicit flow. Use ivar name as key value
|
80
|
+
subbed = ivar.to_s.gsub(/^@/, "")
|
81
|
+
formatted_key = case default_key_type
|
82
|
+
when :strings then subbed
|
83
|
+
when :symbols then subbed.to_sym
|
84
|
+
else
|
85
|
+
# In the event no default settings are provided, default to sym assertion
|
86
|
+
subbed.to_sym
|
87
|
+
end
|
88
|
+
|
89
|
+
# Re-send the original arg
|
90
|
+
[formatted_key, arg]
|
91
|
+
end
|
92
|
+
|
93
|
+
# Lastly, check the ambiguous arg & set the finalized handler
|
94
|
+
out[final_key] = case ambiguous_arg
|
95
|
+
when Proc then ambiguous_arg # It is a dedicated proc handler
|
96
|
+
when Class then ->(fetched_value) { fetched_value.is_a?(ambiguous_arg) } # They want us to typecheck
|
97
|
+
else
|
98
|
+
# Assume bad user input
|
99
|
+
fail ArgumentError, "could not implement validator (supplied arg: #{ambiguous_arg.inspect}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Explicit API to set a key & handler, ignoring case/key-type config
|
105
|
+
def validator(key, handler)
|
106
|
+
# Use our array handling, to specifically bypass key checks
|
107
|
+
instance_variable_set("@#{key}", [key, handler])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Define getters for each of these methods
|
112
|
+
%i[validators guards default_key_case default_key_type].each do |method_name|
|
113
|
+
define_method(method_name) do
|
114
|
+
singleton_class.included_modules.find { |mod|
|
115
|
+
mod.include? Validation
|
116
|
+
}.public_send(method_name)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# TODO: Assert the keys hash conform to a casing stantard
|
122
|
+
def validate_keys!
|
123
|
+
if default_key_type
|
124
|
+
klass = case default_key_type
|
125
|
+
when :symbols then Symbol
|
126
|
+
when :strings then String
|
127
|
+
end
|
128
|
+
|
129
|
+
keys.each do |string_or_sym|
|
130
|
+
Errors::InvalidKeyType.raise!(receiver: self, key: string_or_sym, type: default_key_type) unless string_or_sym.is_a? klass
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
case default_key_case
|
135
|
+
when :lower_snake
|
136
|
+
# TODO
|
137
|
+
when :lowerCamel
|
138
|
+
# TODO
|
139
|
+
when :UpperCamel
|
140
|
+
# TODO
|
141
|
+
when :SCREAMING_SNAKE
|
142
|
+
# TODO
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def validate!
|
147
|
+
validate_keys!
|
148
|
+
|
149
|
+
run_guards!
|
150
|
+
|
151
|
+
# Run validation
|
152
|
+
run_validators!
|
153
|
+
|
154
|
+
# If we reach this line, the schema is valid.
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
def errors
|
159
|
+
@errors ||= []
|
160
|
+
end
|
161
|
+
|
162
|
+
def valid?
|
163
|
+
@errors = []
|
164
|
+
return true if validate!
|
165
|
+
|
166
|
+
# Only rescue lib-defined classes here. Let all other errors surface
|
167
|
+
rescue Errors::InvalidHash, Errors::WontValidate => e
|
168
|
+
@errors = e.error_chain
|
169
|
+
false
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def run_validators!
|
175
|
+
validators.each do |key, handler|
|
176
|
+
hash = fetch(key)
|
177
|
+
|
178
|
+
result = handler.call(hash)
|
179
|
+
Errors::InvalidValue.raise!(key: key, receiver: self) unless result
|
180
|
+
rescue KeyError
|
181
|
+
mod = (singleton_class.included_modules.select { |mod| mod.include? Validation }).first
|
182
|
+
Errors::InvalidHash.raise!("could not validate: #{mod}", key: key, receiver: self)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def run_guards!
|
187
|
+
guards.each do |handler|
|
188
|
+
result = handler.call(self)
|
189
|
+
|
190
|
+
Errors::WontValidate.raise!(receiver: self) unless result
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
data/lib/bhm/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bhm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Trevor James
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-09-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: amazing_print
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry-byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: standard
|
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
|
+
description:
|
84
|
+
email: trevor@osrs-stat.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- README.md
|
90
|
+
- examples/meta.rb
|
91
|
+
- examples/team.rb
|
92
|
+
- examples/user.rb
|
93
|
+
- lib/bhm.rb
|
94
|
+
- lib/bhm/errors.rb
|
95
|
+
- lib/bhm/scaffold.rb
|
96
|
+
- lib/bhm/utils.rb
|
97
|
+
- lib/bhm/validation.rb
|
98
|
+
- lib/bhm/version.rb
|
99
|
+
homepage: https://github.com/fire-pls/bhm
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata: {}
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 2.6.6
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 2.7.4
|
117
|
+
requirements: []
|
118
|
+
rubygems_version: 3.0.3
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: Modular hash validation
|
122
|
+
test_files: []
|