key-value-parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,7 @@
1
+ .DS_STORE
2
+ *.swp
3
+ *.sass-cache
4
+ pkg/
5
+ Gemfile.lock
6
+ .bundle/
7
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem 'minitest', '>=5.8.0'
4
+
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
+
@@ -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