key_value_name 0.0.1
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 +72 -0
- data/lib/key_value_name.rb +26 -0
- data/lib/key_value_name/builder.rb +91 -0
- data/lib/key_value_name/marshalers.rb +11 -0
- data/lib/key_value_name/marshalers/base.rb +23 -0
- data/lib/key_value_name/marshalers/numeric_marshaler.rb +44 -0
- data/lib/key_value_name/marshalers/symbol_marshaler.rb +21 -0
- data/lib/key_value_name/spec.rb +52 -0
- data/lib/key_value_name/version.rb +8 -0
- data/test/key_value_name/key_value_name_test.rb +147 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c1f8780bde799ea40e2fd042acd3893a16d506b1
|
4
|
+
data.tar.gz: 0c8a821f32cf6cbdd8681c559f27498011d64e25
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b13cf37a899c2be009c01cc3f94da5068bc2c495901f217d72f715444e8118f191cb96fcf9553527ac4f3f5879220c1a898e6a93d6c2545c8908462cf8dc8e34
|
7
|
+
data.tar.gz: eee937f19b07d827f3bd5bdf65b7c1b93935e8d4fe7f222b85c3f3e7afa0be570d008b1466db312ebff6bfab378e40c9e4712ca437e31e8ebd43318b470af650
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# key_value_name
|
2
|
+
|
3
|
+
* https://github.com/jdleesmiller/key_value_name
|
4
|
+
|
5
|
+
## Synopsis
|
6
|
+
|
7
|
+
Store key-value pairs in file names, for example parameter names and parameters for experiments or simulation runs.
|
8
|
+
|
9
|
+
This gem provides:
|
10
|
+
|
11
|
+
1. Some standard naming conventions that work well across platforms by avoiding special characters in file names.
|
12
|
+
|
13
|
+
2. Automatic formatting and type conversion for the parameters.
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
```rb
|
18
|
+
require 'key_value_name'
|
19
|
+
|
20
|
+
ResultName = KeyValueName.new do |n|
|
21
|
+
n.key :seed, type: Numeric, format: '%d'
|
22
|
+
n.key :algorithm, type: Symbol
|
23
|
+
n.key :alpha, type: Numeric
|
24
|
+
n.extension :dat
|
25
|
+
end
|
26
|
+
|
27
|
+
name = ResultName.new(
|
28
|
+
seed: 123,
|
29
|
+
algorithm: :reticulating_splines,
|
30
|
+
alpha: 42.1)
|
31
|
+
|
32
|
+
name.to_s
|
33
|
+
# => seed-123.algorithm-reticulating_splines.alpha-42.1.dat
|
34
|
+
|
35
|
+
name.in('/tmp')
|
36
|
+
# => /tmp/seed-123.algorithm-reticulating_splines.alpha-42.1.dat
|
37
|
+
|
38
|
+
# Assuming a matching file exists in /tmp.
|
39
|
+
ResultName.glob('/tmp')
|
40
|
+
# => [#<struct ResultName seed=123, algorithm=:reticulating_splines, alpha=42.1>]
|
41
|
+
```
|
42
|
+
|
43
|
+
## INSTALLATION
|
44
|
+
|
45
|
+
```
|
46
|
+
gem install key_value_name
|
47
|
+
```
|
48
|
+
|
49
|
+
## LICENSE
|
50
|
+
|
51
|
+
(The MIT License)
|
52
|
+
|
53
|
+
Copyright (c) 2017 John Lees-Miller
|
54
|
+
|
55
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
56
|
+
a copy of this software and associated documentation files (the
|
57
|
+
'Software'), to deal in the Software without restriction, including
|
58
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
59
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
60
|
+
permit persons to whom the Software is furnished to do so, subject to
|
61
|
+
the following conditions:
|
62
|
+
|
63
|
+
The above copyright notice and this permission notice shall be
|
64
|
+
included in all copies or substantial portions of the Software.
|
65
|
+
|
66
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
67
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
68
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
69
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
70
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
71
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
72
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# A terrible idea, but also a useful one.
|
5
|
+
#
|
6
|
+
module KeyValueName
|
7
|
+
KEY_RX = /\w+/
|
8
|
+
KEY_VALUE_SEPARATOR = '-'
|
9
|
+
PAIR_SEPARATOR = '.'
|
10
|
+
PAIR_SEPARATOR_RX = /[.]/
|
11
|
+
|
12
|
+
def self.check_symbol(name)
|
13
|
+
raise ArgumentError, "bad symbol: #{name}" unless name =~ /\A#{KEY_RX}\z/
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.new
|
17
|
+
builder = Builder.new
|
18
|
+
yield builder
|
19
|
+
builder.build
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require_relative 'key_value_name/version'
|
24
|
+
require_relative 'key_value_name/marshalers'
|
25
|
+
require_relative 'key_value_name/spec'
|
26
|
+
require_relative 'key_value_name/builder'
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeyValueName
|
4
|
+
#
|
5
|
+
# Yield-based Domain-Specific Language (DSL) to build a `KeyValueName`.
|
6
|
+
#
|
7
|
+
class Builder
|
8
|
+
#
|
9
|
+
# Class methods of the returned `KeyValueName` class.
|
10
|
+
#
|
11
|
+
module ClassMethods
|
12
|
+
def read_hash(name)
|
13
|
+
key_value_name_spec.read(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def read(name)
|
17
|
+
new(read_hash(name))
|
18
|
+
end
|
19
|
+
|
20
|
+
def glob(path)
|
21
|
+
Dir.glob(File.join(path, '*')).map do |name|
|
22
|
+
basename = File.basename(name)
|
23
|
+
new(read_hash(basename)) if key_value_name_spec.matches?(basename)
|
24
|
+
end.compact
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Instance methods of the returned `KeyValueName` class.
|
30
|
+
#
|
31
|
+
module InstanceMethods
|
32
|
+
def in(folder)
|
33
|
+
File.join(folder, to_s)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
self.class.key_value_name_spec.write(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@marshalers = {}
|
43
|
+
@extension = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def include_keys(key_value_name_klass)
|
47
|
+
spec = key_value_name_klass.key_value_name_spec
|
48
|
+
spec.marshalers.each do |name, marshaler|
|
49
|
+
check_no_existing_marshaler(name)
|
50
|
+
@marshalers[name] = marshaler
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def key(name, type:, **kwargs)
|
55
|
+
KeyValueName.check_symbol(name)
|
56
|
+
raise ArgumentError, "bad type: #{type}" unless MARSHALERS.key?(type)
|
57
|
+
check_no_existing_marshaler(name)
|
58
|
+
@marshalers[name] = MARSHALERS[type].new(**kwargs)
|
59
|
+
end
|
60
|
+
|
61
|
+
def extension(ext) # rubocop:disable Style/TrivialAccessors
|
62
|
+
@extension = ext
|
63
|
+
end
|
64
|
+
|
65
|
+
def build # rubocop:disable Metrics/MethodLength
|
66
|
+
raise 'no keys defined' if @marshalers.none?
|
67
|
+
|
68
|
+
klass = Struct.new(*@marshalers.keys) do
|
69
|
+
def initialize(**kwargs)
|
70
|
+
super(*kwargs.keys)
|
71
|
+
kwargs.each { |k, v| self[k] = v }
|
72
|
+
end
|
73
|
+
|
74
|
+
include InstanceMethods
|
75
|
+
|
76
|
+
class <<self
|
77
|
+
include ClassMethods
|
78
|
+
attr_accessor :key_value_name_spec
|
79
|
+
end
|
80
|
+
end
|
81
|
+
klass.key_value_name_spec = Spec.new(@marshalers, @extension)
|
82
|
+
klass
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def check_no_existing_marshaler(key)
|
88
|
+
raise ArgumentError, "already have key: #{key}" if @marshalers.key?(key)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'marshalers/base'
|
3
|
+
require_relative 'marshalers/numeric_marshaler'
|
4
|
+
require_relative 'marshalers/symbol_marshaler'
|
5
|
+
|
6
|
+
module KeyValueName
|
7
|
+
MARSHALERS = {
|
8
|
+
Numeric => NumericMarshaler,
|
9
|
+
Symbol => SymbolMarshaler
|
10
|
+
}.freeze
|
11
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeyValueName
|
4
|
+
#
|
5
|
+
# A Marshaler handles conversion of typed values to and from strings.
|
6
|
+
#
|
7
|
+
class MarshalerBase
|
8
|
+
def initialize(**kwargs)
|
9
|
+
end
|
10
|
+
|
11
|
+
def matcher
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def read(_string)
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
def write(_value)
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'scanf'
|
4
|
+
|
5
|
+
module KeyValueName
|
6
|
+
#
|
7
|
+
# Read and write numeric types with a general format string for
|
8
|
+
# `Kernel#format` (or `Kernel#sprintf`) and `String#scanf`.
|
9
|
+
#
|
10
|
+
# This seems like a nice idea, but ruby's `scanf` doesn't seem to handle
|
11
|
+
# all possible format strings. For example, you can format with `%.1f`, but
|
12
|
+
# scanning with that string does not work. To work around this problem,
|
13
|
+
# you can specify a separate `scan_format` that `scanf` can handle; for this
|
14
|
+
# example, it would be just `%f`.
|
15
|
+
#
|
16
|
+
class NumericMarshaler < MarshalerBase
|
17
|
+
def initialize(format: '%g', scan_format: nil)
|
18
|
+
@format_string = format
|
19
|
+
@scan_format_string = scan_format
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :format_string
|
23
|
+
|
24
|
+
def scan_format_string
|
25
|
+
@scan_format_string || format_string
|
26
|
+
end
|
27
|
+
|
28
|
+
def matcher
|
29
|
+
# This is the usual regex, except that it also has to match `%x` formats,
|
30
|
+
# so it allows hexadecimal whole numbers.
|
31
|
+
/[-+]?[0-9]*\.?[0-9a-f]+(?:e[-+]?[0-9]+)?/i
|
32
|
+
end
|
33
|
+
|
34
|
+
def read(string)
|
35
|
+
values = string.scanf(scan_format_string)
|
36
|
+
raise "failed to scan: #{string}" if values.empty?
|
37
|
+
values.first
|
38
|
+
end
|
39
|
+
|
40
|
+
def write(value)
|
41
|
+
format(format_string, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeyValueName
|
4
|
+
#
|
5
|
+
# Read and write symbol values.
|
6
|
+
#
|
7
|
+
class SymbolMarshaler < MarshalerBase
|
8
|
+
def matcher
|
9
|
+
KEY_RX
|
10
|
+
end
|
11
|
+
|
12
|
+
def read(string)
|
13
|
+
string.to_sym
|
14
|
+
end
|
15
|
+
|
16
|
+
def write(value)
|
17
|
+
KeyValueName.check_symbol(value)
|
18
|
+
value.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeyValueName
|
4
|
+
#
|
5
|
+
# Specify the keys and value types for a KeyValueName.
|
6
|
+
#
|
7
|
+
class Spec
|
8
|
+
def initialize(marshalers, extension)
|
9
|
+
@marshalers = marshalers
|
10
|
+
@extension = extension
|
11
|
+
@matcher = build_matcher
|
12
|
+
|
13
|
+
marshalers.freeze
|
14
|
+
freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :marshalers
|
18
|
+
attr_reader :extension
|
19
|
+
attr_reader :matcher
|
20
|
+
|
21
|
+
def matches?(string)
|
22
|
+
string =~ matcher
|
23
|
+
end
|
24
|
+
|
25
|
+
def read(string)
|
26
|
+
raise ArgumentError, "bad filename: #{string}" unless string =~ matcher
|
27
|
+
Hash[marshalers.map.with_index do |(key, marshaler), index|
|
28
|
+
[key, marshaler.read(Regexp.last_match(index + 1))]
|
29
|
+
end]
|
30
|
+
end
|
31
|
+
|
32
|
+
def write(name)
|
33
|
+
string = name.each_pair.map do |key, value|
|
34
|
+
value_string = marshalers[key].write(value)
|
35
|
+
"#{key}#{KEY_VALUE_SEPARATOR}#{value_string}"
|
36
|
+
end.join(PAIR_SEPARATOR)
|
37
|
+
string += ".#{extension}" unless extension.nil?
|
38
|
+
string
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def build_matcher
|
44
|
+
pair_rxs = marshalers.map do |name, marshaler|
|
45
|
+
/#{name}#{KEY_VALUE_SEPARATOR}(#{marshaler.matcher})/
|
46
|
+
end
|
47
|
+
pairs_matcher = pair_rxs.map(&:to_s).join(PAIR_SEPARATOR_RX.to_s)
|
48
|
+
extension_matcher = extension.nil? ? '' : /[.]#{extension}/.to_s
|
49
|
+
Regexp.new('\A' + pairs_matcher + extension_matcher + '\z')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
require 'key_value_name'
|
8
|
+
|
9
|
+
class TestKeyValueName < MiniTest::Test
|
10
|
+
TestInteger = KeyValueName.new do |n|
|
11
|
+
n.key :a, type: Numeric, format: '%d'
|
12
|
+
end
|
13
|
+
|
14
|
+
TestHexNumeric = KeyValueName.new do |n|
|
15
|
+
n.key :b, type: Numeric, format: '%x'
|
16
|
+
end
|
17
|
+
|
18
|
+
TestFormattedNumeric = KeyValueName.new do |n|
|
19
|
+
n.key :c, type: Numeric, format: '%.3f', scan_format: '%f'
|
20
|
+
end
|
21
|
+
|
22
|
+
TestPaddedNumeric = KeyValueName.new do |n|
|
23
|
+
n.key :d, type: Numeric, format: '%04d'
|
24
|
+
end
|
25
|
+
|
26
|
+
TestSymbol = KeyValueName.new do |n|
|
27
|
+
n.key :a, type: Symbol
|
28
|
+
end
|
29
|
+
|
30
|
+
TestFloat = KeyValueName.new do |n|
|
31
|
+
n.key :a, type: Numeric
|
32
|
+
end
|
33
|
+
|
34
|
+
TestTwoIntegers = KeyValueName.new do |n|
|
35
|
+
n.include_keys TestInteger
|
36
|
+
n.include_keys TestHexNumeric
|
37
|
+
end
|
38
|
+
|
39
|
+
TestMixed = KeyValueName.new do |n|
|
40
|
+
n.key :id, type: Symbol
|
41
|
+
n.key :ordinal, type: Numeric, format: '%d'
|
42
|
+
n.key :value, type: Numeric
|
43
|
+
end
|
44
|
+
|
45
|
+
TestExtension = KeyValueName.new do |n|
|
46
|
+
n.key :big_number, type: Numeric, format: '%04d'
|
47
|
+
n.extension 'bin'
|
48
|
+
end
|
49
|
+
|
50
|
+
TestEKey = KeyValueName.new do |n|
|
51
|
+
n.key :x, type: Numeric
|
52
|
+
n.key :e, type: Numeric
|
53
|
+
end
|
54
|
+
|
55
|
+
def roundtrip(klass, string, args)
|
56
|
+
name = klass.read(string)
|
57
|
+
assert_equal args.keys, name.to_h.keys
|
58
|
+
args.each do |key, value|
|
59
|
+
assert_equal value, name[key]
|
60
|
+
end
|
61
|
+
assert_equal string, name.to_s
|
62
|
+
name
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_integer_roundtrip
|
66
|
+
roundtrip(TestInteger, 'a-123', a: 123)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_hex_numeric_roundtrip
|
70
|
+
roundtrip(TestHexNumeric, 'b-ff', b: 255)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_formatted_numeric_roundtrip
|
74
|
+
roundtrip(TestFormattedNumeric, 'c-0.100', c: 0.1)
|
75
|
+
roundtrip(TestFormattedNumeric, 'c--0.200', c: -0.2)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_formatted_numeric_parse
|
79
|
+
assert_equal(-0.0013, TestFormattedNumeric.read('c--1.3e-3').c)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_padded_numeric_roundtrip
|
83
|
+
roundtrip(TestPaddedNumeric, 'd-0012', d: 12)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_symbol_roundtrip
|
87
|
+
roundtrip(TestSymbol, 'a-foo', a: :foo)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_symbol_accepts_strings
|
91
|
+
assert_equal 'a-foo', TestSymbol.new(a: 'foo').to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_float_roundtrip
|
95
|
+
roundtrip(TestFloat, 'a-2.25', a: 2.25)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_two_integers_roundtrip
|
99
|
+
roundtrip(TestTwoIntegers, 'a-123.b-ff', a: 123, b: 255)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_mixed_roundtrip
|
103
|
+
name = roundtrip(
|
104
|
+
TestMixed,
|
105
|
+
'id-foo.ordinal-1234.value-2.5e-11',
|
106
|
+
id: :foo, ordinal: 1234, value: 2.5e-11
|
107
|
+
)
|
108
|
+
assert_equal :foo, name.id
|
109
|
+
assert_equal 1234, name.ordinal
|
110
|
+
assert_equal 2.5e-11, name.value
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_extension_roundtrip
|
114
|
+
roundtrip(TestExtension, 'big_number-0123.bin', big_number: 123)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_e_key_roundtrip
|
118
|
+
# A file name called `x-1.e-2` could mean `x=1e-2` or `x=1`, `e=2`. It's
|
119
|
+
# still possible to distinguish between them if we know that we're looking
|
120
|
+
# for two keys.
|
121
|
+
roundtrip(TestEKey, 'x-1.e-2', x: 1, e: 2)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_missing_key
|
125
|
+
assert_raises do
|
126
|
+
TestInteger.new(b: 3)
|
127
|
+
end
|
128
|
+
assert_raises(ArgumentError) do
|
129
|
+
TestInteger.read('b-3')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_in_folder
|
134
|
+
assert_equal File.join('foo', 'a-1'), TestInteger.new(a: 1).in('foo')
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_glob_with_integers
|
138
|
+
Dir.mktmpdir do |tmp|
|
139
|
+
FileUtils.touch TestInteger.new(a: 1).in(tmp)
|
140
|
+
FileUtils.touch TestInteger.new(a: 2).in(tmp)
|
141
|
+
names = TestInteger.glob(tmp).sort_by(&:a)
|
142
|
+
assert_equal 2, names.size
|
143
|
+
assert_equal 1, names[0].a
|
144
|
+
assert_equal 2, names[1].a
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: key_value_name
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Lees-Miller
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gemma
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.1.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.1.0
|
27
|
+
description: Store key-value pairs in file names, e.g. parameter names and parameters.
|
28
|
+
email:
|
29
|
+
- jdleesmiller@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files:
|
33
|
+
- README.md
|
34
|
+
files:
|
35
|
+
- README.md
|
36
|
+
- lib/key_value_name.rb
|
37
|
+
- lib/key_value_name/builder.rb
|
38
|
+
- lib/key_value_name/marshalers.rb
|
39
|
+
- lib/key_value_name/marshalers/base.rb
|
40
|
+
- lib/key_value_name/marshalers/numeric_marshaler.rb
|
41
|
+
- lib/key_value_name/marshalers/symbol_marshaler.rb
|
42
|
+
- lib/key_value_name/spec.rb
|
43
|
+
- lib/key_value_name/version.rb
|
44
|
+
- test/key_value_name/key_value_name_test.rb
|
45
|
+
homepage: https://github.com/jdleesmiller/key_value_name
|
46
|
+
licenses: []
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- "--main"
|
51
|
+
- README.md
|
52
|
+
- "--title"
|
53
|
+
- key_value_name-0.0.1 Documentation
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 2.6.8
|
69
|
+
signing_key:
|
70
|
+
specification_version: 4
|
71
|
+
summary: Store key-value pairs in file names, e.g. parameter names and parameters.
|
72
|
+
test_files:
|
73
|
+
- test/key_value_name/key_value_name_test.rb
|