key-value-parser 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/.gitignore +7 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +183 -0
- data/key-value-parser.gemspec +19 -0
- data/lib/key_value_parser.rb +54 -0
- data/test/test_key_value_parser.rb +112 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d2e00095ab20a6984d6ad8a602c5e1c71181a509
|
4
|
+
data.tar.gz: 0dd0fc09982b0d55bfdbabbda65b3eee147d702d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9457a9ebe4c75ce381ef2f0e007827e3cd6ea396f944a7aa5db0037fb7972b21e3c7b22f7c8ca9f0895ab9e52f89d49c210cd08ca69f94407fe27438355c58d4
|
7
|
+
data.tar.gz: 78f7b302139bad8523391c15e603835ef44d6fff3dce1b4eab48080efcfcf2dcdbf156a80319bd1eca7e9dd1d427c6eeb00c67ac2fac2b8490258e7f96fcb063
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2016 Mickael Riga
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
data/README.md
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
Key Value Parser
|
2
|
+
================
|
3
|
+
|
4
|
+
The primary purpose of `KeyValueParser` is to have a
|
5
|
+
simple class to be able to parse command line arguments
|
6
|
+
which are all formated as `key:value`.
|
7
|
+
|
8
|
+
For example you could call a script like this:
|
9
|
+
|
10
|
+
```
|
11
|
+
$ ruby my-script.rb port=3000 host=localhost user=bob
|
12
|
+
```
|
13
|
+
|
14
|
+
Then in your script you would do:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# my-script.rb
|
18
|
+
|
19
|
+
require 'key_value_parser'
|
20
|
+
|
21
|
+
options = KeyValueParser.new.parse(ARGV)
|
22
|
+
options[:port] == 3000
|
23
|
+
options[:host] == 'localhost'
|
24
|
+
options[:user] == 'bob'
|
25
|
+
```
|
26
|
+
|
27
|
+
Since `KeyValueParser` is quite opinionated, it is absolutely
|
28
|
+
not a replacement for `OptionParser` which aim is to be able to
|
29
|
+
parse Unix style arguments.
|
30
|
+
|
31
|
+
Also `KeyValueParser` is not limited to command line arguments.
|
32
|
+
It can potentially parse any array which is a list of Key/Value
|
33
|
+
strings. For example you can parse a list of HTTP header lines.
|
34
|
+
|
35
|
+
The following sections are list of features in order to understand
|
36
|
+
what `KeyValueParser` can and cannot do.
|
37
|
+
|
38
|
+
Default Values
|
39
|
+
--------------
|
40
|
+
|
41
|
+
When you create the parser instance, you can pass a `Hash` with
|
42
|
+
default values.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
# $ ruby my-script.rb host=www.domain.com
|
46
|
+
parser = KeyValueParser.new host: 'localhost', port: 3000
|
47
|
+
options = parser.parse(ARGV)
|
48
|
+
options[:port] == 3000
|
49
|
+
options[:host] == 'www.domain.com'
|
50
|
+
```
|
51
|
+
|
52
|
+
Typecasted Values
|
53
|
+
-----------------
|
54
|
+
|
55
|
+
As you may have noticed in previous examples, values are
|
56
|
+
typecasted. So far it does typecast integers and booleans.
|
57
|
+
Also if you don't give a value, the parser will interpret
|
58
|
+
it as a flag and set it to `true`.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
# $ ruby myscript.rb port=3000 broadcast=false running
|
62
|
+
options = KeyValueParser.new.parse(ARGV)
|
63
|
+
options[:port] == 3000
|
64
|
+
options[:broadcast] == false
|
65
|
+
options[:running] == true
|
66
|
+
```
|
67
|
+
|
68
|
+
If you don't want to cast values, you can use the second of
|
69
|
+
`KeyValueParse#parse` which is a list of options. Just set
|
70
|
+
`typecast_values` to `false`.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
parser = KeyValueparser.new({}, {typecast_values: false})
|
74
|
+
```
|
75
|
+
|
76
|
+
Typecasting is still very basic and will most likely evolve,
|
77
|
+
but it will move in this direction.
|
78
|
+
|
79
|
+
Normalized Keys
|
80
|
+
---------------
|
81
|
+
|
82
|
+
Keys of the resulting `Hash` are normalized. Dash in the middle
|
83
|
+
of words are replaced by underscores. Double dash in front of a
|
84
|
+
word are also removed. It allows you to have unix style dash
|
85
|
+
arguments.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
# $ ruby my-script.rb --user-name="bob mould"
|
89
|
+
options = KeyValueParser.new.parse(ARGV)
|
90
|
+
options[:user_name] == 'bob'
|
91
|
+
```
|
92
|
+
|
93
|
+
Because of the way command line arguments are created for `ARGV`
|
94
|
+
you can even surround an argument with quotes in order to have
|
95
|
+
spaces in the arguments value.
|
96
|
+
|
97
|
+
There is nothing yet for unix style single dash arguments.
|
98
|
+
I could remove the dash and treat it like a single letter key,
|
99
|
+
but the true purpose of single letter arguments is to be an
|
100
|
+
alternative to a longer argument name. If you have a simple idea
|
101
|
+
to implement this without too much hassle, please send me a pull
|
102
|
+
request.
|
103
|
+
|
104
|
+
If you don't want the keys to be normalized, there is an option
|
105
|
+
for this.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
# $ ruby my-script.rb --user-name=bob
|
109
|
+
parser = KeyValueParser.new({}, {normalize_keys: false})
|
110
|
+
options = parser.parse(ARGV)
|
111
|
+
options['--user-name'] == 'bob'
|
112
|
+
```
|
113
|
+
|
114
|
+
Array Arguments
|
115
|
+
---------------
|
116
|
+
|
117
|
+
You can have array values if you chain more than one `=<value>`
|
118
|
+
after the key. And the values are still typecasted unless you
|
119
|
+
disable it.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
# $ ruby my-script.rb heroes=batman=robin ids=1=2
|
123
|
+
options = KeyValueParser.new.parse(ARGV)
|
124
|
+
options[:heroes] == ['batman', 'robin']
|
125
|
+
options[:ids] == [1, 2]
|
126
|
+
```
|
127
|
+
|
128
|
+
You can also disable this option:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
# $ ruby my-script.rb heroes=batman=robin
|
132
|
+
parser = KeyValueParser.new({}, {array_values: false})
|
133
|
+
options = parser.parse(ARGV)
|
134
|
+
options[:heroes] == 'batman=robin'
|
135
|
+
```
|
136
|
+
|
137
|
+
Please note that so far this is the only way to make an array.
|
138
|
+
Setting multiple times the same value would just result
|
139
|
+
in the key being set to the last value.
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
# $ ruby my-script.rb heroes=batman heroes=robin
|
143
|
+
options = KeyValueParser.new.parse(ARGV)
|
144
|
+
options[:heroes] == 'robin'
|
145
|
+
```
|
146
|
+
|
147
|
+
Parsing More Than ARGV
|
148
|
+
----------------------
|
149
|
+
|
150
|
+
By default, the separator allows you to have an equal sign `=`
|
151
|
+
or a colon `:`. And the regexp allows spaces around the separator.
|
152
|
+
The surrounded spaces are if you want to parse a list of keys/values
|
153
|
+
from a file for example. Let say you have a file containing a
|
154
|
+
key/value per line.
|
155
|
+
|
156
|
+
```
|
157
|
+
user: Bob Mould
|
158
|
+
number: 42
|
159
|
+
```
|
160
|
+
|
161
|
+
Which looks like a subset of YAML.
|
162
|
+
Then you can parse the file for settings.
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
parser = KeyValueParser.new
|
166
|
+
settings = parser.parse File.readlines('settings.conf')
|
167
|
+
```
|
168
|
+
Everything works the same, typecasting, normalizing keys, defaults, arrays...
|
169
|
+
You can also set another separator. Anything which works with
|
170
|
+
`String#split` will do.
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
# settings.conf:
|
174
|
+
# author | Kevin Smith
|
175
|
+
# characters | Jay | Silent Bob
|
176
|
+
|
177
|
+
parser = KeyValueParser.new({stars: 5}, {separator: /\s*\|\s*/})
|
178
|
+
settings = parser.parse File.readlines('settings.conf')
|
179
|
+
settings[:author] == 'Kevin Smith'
|
180
|
+
settings[:characters] == ['Jay', 'Silent Bob']
|
181
|
+
settings[:stars] == 5
|
182
|
+
```
|
183
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
|
3
|
+
s.authors = ["Mickael Riga"]
|
4
|
+
s.email = ["mig@mypeplum.com"]
|
5
|
+
s.homepage = "https://github.com/mig-hub/key-value-parser"
|
6
|
+
s.licenses = ['MIT']
|
7
|
+
|
8
|
+
s.name = 'key-value-parser'
|
9
|
+
s.version = '0.0.1'
|
10
|
+
s.summary = "Key Value Parser"
|
11
|
+
s.description = "KeyValueParser parses arrays of string options like 'machine=coconut'. It is mainly done for parsing ARGV, but can be used for other things."
|
12
|
+
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
s.files = `git ls-files`.split("\n").sort
|
15
|
+
s.test_files = s.files.grep(/^test\//)
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class KeyValueParser
|
2
|
+
|
3
|
+
def initialize defaults={}, options={}
|
4
|
+
@defaults = defaults
|
5
|
+
@options = {
|
6
|
+
separator: /\s*[=:]\s*/,
|
7
|
+
normalize_keys: true,
|
8
|
+
typecast_values: true,
|
9
|
+
array_values: true
|
10
|
+
}.merge(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse kvs
|
14
|
+
@defaults.merge(
|
15
|
+
Hash[
|
16
|
+
kvs.map do |a|
|
17
|
+
k, *v = a.split(@options[:separator], @options[:array_values] ? 0 : 2)
|
18
|
+
if v.size==1
|
19
|
+
v = v[0]
|
20
|
+
elsif v.size==0
|
21
|
+
v = nil
|
22
|
+
end
|
23
|
+
[
|
24
|
+
@options[:normalize_keys] ? normalize_key(k) : k,
|
25
|
+
@options[:typecast_values] ? typecast(v) : v
|
26
|
+
]
|
27
|
+
end
|
28
|
+
]
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def normalize_key k
|
35
|
+
k.sub(/^--/,'').gsub(/[\s\-]+/, '_').to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
def typecast v
|
39
|
+
if v.is_a? Array
|
40
|
+
return v.map{|item| typecast(item)}
|
41
|
+
end
|
42
|
+
if v=='true' or v.nil?
|
43
|
+
v = true
|
44
|
+
elsif v=='false'
|
45
|
+
v = false
|
46
|
+
elsif v=~/^\d+$/
|
47
|
+
v = v.to_i
|
48
|
+
else
|
49
|
+
v
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'key_value_parser'
|
3
|
+
|
4
|
+
class TestKeyValueParser < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@parser = KeyValueParser.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_parses_kvs
|
11
|
+
kvs = ['user:mig', 'machine:coconut']
|
12
|
+
expected = {user: 'mig', machine: 'coconut'}
|
13
|
+
assert_equal expected, @parser.parse(kvs)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_equal_works_as_separator
|
17
|
+
kvs = ['user=mig', 'machine=coconut']
|
18
|
+
expected = {user: 'mig', machine: 'coconut'}
|
19
|
+
assert_equal expected, @parser.parse(kvs)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_spaces_work_in_separator
|
23
|
+
kvs = ['user= mig', 'machine = coconut']
|
24
|
+
expected = {user: 'mig', machine: 'coconut'}
|
25
|
+
assert_equal expected, @parser.parse(kvs)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_booleans_are_typecasted
|
29
|
+
kvs = ['dead:false', 'running:true']
|
30
|
+
expected = {dead: false, running: true}
|
31
|
+
assert_equal expected, @parser.parse(kvs)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_integers_are_typecasted
|
35
|
+
kvs = ['machine:coconut', 'size:11']
|
36
|
+
expected = {machine: 'coconut', size: 11}
|
37
|
+
assert_equal expected, @parser.parse(kvs)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_nil_value_typecasted_to_true
|
41
|
+
kvs = ['running']
|
42
|
+
expected = {running: true}
|
43
|
+
assert_equal expected, @parser.parse(kvs)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_parser_can_have_defaults
|
47
|
+
kvs = ['user:mig']
|
48
|
+
expected = {user: 'mig', role: 'dev'}
|
49
|
+
parser = KeyValueParser.new user: 'marty', role: 'dev'
|
50
|
+
assert_equal expected, parser.parse(kvs)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_separator_can_be_changed
|
54
|
+
kvs = ['user|mig', 'machine|coconut']
|
55
|
+
expected = {user: 'mig', machine: 'coconut'}
|
56
|
+
wrong_parser = KeyValueParser.new
|
57
|
+
refute_equal expected, wrong_parser.parse(kvs)
|
58
|
+
parser = KeyValueParser.new({}, separator: '|')
|
59
|
+
assert_equal expected, parser.parse(kvs)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_keys_are_normalized
|
63
|
+
kvs = ['user-name=mig', 'machine_name=coconut', 'why not=yes']
|
64
|
+
expected = {user_name: 'mig', machine_name: 'coconut', why_not: 'yes'}
|
65
|
+
assert_equal expected, @parser.parse(kvs)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_unix_double_dash_keys_are_normalized
|
69
|
+
kvs = ['--user-name=mig', '--running']
|
70
|
+
expected = {user_name: 'mig', running: true}
|
71
|
+
assert_equal expected, @parser.parse(kvs)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_value_is_updated_if_key_is_referenced_multiple_times
|
75
|
+
kvs = ['user:bad', 'user:mig']
|
76
|
+
expected = {user: 'mig'}
|
77
|
+
assert_equal expected, @parser.parse(kvs)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_arrays
|
81
|
+
kvs = ['users:mig:why', 'numbers:3:5', 'request:false:POST:500']
|
82
|
+
expected = {
|
83
|
+
users: ['mig', 'why'],
|
84
|
+
numbers: [3,5],
|
85
|
+
request: [false, 'POST', 500]
|
86
|
+
}
|
87
|
+
assert_equal expected, @parser.parse(kvs)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_normalize_key_can_be_skipped
|
91
|
+
kvs = ['--user-name=mig', '--running']
|
92
|
+
expected = {'--user-name' => 'mig', '--running' => true}
|
93
|
+
parser = KeyValueParser.new({}, {normalize_keys: false})
|
94
|
+
assert_equal expected, parser.parse(kvs)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_typecast_can_be_skipped
|
98
|
+
kvs = ['user:mig', 'size:5', 'crazy:false:maybe', 'dev']
|
99
|
+
expected = {user: 'mig', size: '5', crazy: ['false','maybe'], dev: nil}
|
100
|
+
parser = KeyValueParser.new({}, {typecast_values: false})
|
101
|
+
assert_equal expected, parser.parse(kvs)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_arrays_can_be_avoided
|
105
|
+
kvs = ['users:mig=why', 'size:5:6', 'running']
|
106
|
+
expected = {users: 'mig=why', size: '5:6', running: true}
|
107
|
+
parser = KeyValueParser.new({}, {array_values: false})
|
108
|
+
assert_equal expected, parser.parse(kvs)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: key-value-parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mickael Riga
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-24 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: KeyValueParser parses arrays of string options like 'machine=coconut'.
|
14
|
+
It is mainly done for parsing ARGV, but can be used for other things.
|
15
|
+
email:
|
16
|
+
- mig@mypeplum.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- ".gitignore"
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- key-value-parser.gemspec
|
26
|
+
- lib/key_value_parser.rb
|
27
|
+
- test/test_key_value_parser.rb
|
28
|
+
homepage: https://github.com/mig-hub/key-value-parser
|
29
|
+
licenses:
|
30
|
+
- MIT
|
31
|
+
metadata: {}
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 2.4.5.1
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: Key Value Parser
|
52
|
+
test_files:
|
53
|
+
- test/test_key_value_parser.rb
|