bhm 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|