key_value_name 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|