kvn 0.1.0 → 0.2.0
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 +4 -4
- data/Gemfile.lock +2 -16
- data/README.md +44 -1
- data/lib/kvn.rb +15 -28
- data/lib/kvn/converter.rb +38 -0
- data/lib/kvn/lexer.rb +4 -4
- data/lib/kvn/parser.rb +42 -14
- data/lib/kvn/unsupported_hash_error.rb +4 -0
- data/lib/kvn/value_lexer.rb +21 -0
- data/lib/kvn/version.rb +1 -1
- metadata +5 -3
- data/lib/kvn/illegal_character_error.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 832c9ff0fe7496bfe3c6f5a93cc7b959e8889cb2
|
4
|
+
data.tar.gz: 05dd1ba7428b883dc2fe7669ae70fa180f14c383
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ec2564e05c43f19bd5897d58cf7bda7392817ce7bcb738e44abec846deccc332893d292565b9855605385462383d7309164ee52729f3060ccd7808cdfbbf28c
|
7
|
+
data.tar.gz: 2f00b76e616acf6177ca67558004c89545fb9adb0a616fac958f3eabc9c28db556ac626cb36bc563bc02f12fb0d37dffa6ec2d5d7f09c4fcdd7e3b176fd9a761
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
kvn (0.
|
4
|
+
kvn (0.2.0)
|
5
5
|
lex (= 0.1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -11,25 +11,18 @@ GEM
|
|
11
11
|
debug_inspector (>= 0.0.1)
|
12
12
|
byebug (8.2.2)
|
13
13
|
coderay (1.1.1)
|
14
|
-
coveralls (0.8.
|
14
|
+
coveralls (0.8.13)
|
15
15
|
json (~> 1.8)
|
16
|
-
rest-client (>= 1.6.8, < 2)
|
17
16
|
simplecov (~> 0.11.0)
|
18
17
|
term-ansicolor (~> 1.3)
|
19
18
|
thor (~> 0.19.1)
|
20
19
|
tins (~> 1.6.0)
|
21
20
|
debug_inspector (0.0.2)
|
22
21
|
docile (1.1.5)
|
23
|
-
domain_name (0.5.20160128)
|
24
|
-
unf (>= 0.0.5, < 1.0.0)
|
25
|
-
http-cookie (1.0.2)
|
26
|
-
domain_name (~> 0.5)
|
27
22
|
interception (0.5)
|
28
23
|
json (1.8.3)
|
29
24
|
lex (0.1.0)
|
30
25
|
method_source (0.8.2)
|
31
|
-
mime-types (2.99.1)
|
32
|
-
netrc (0.11.0)
|
33
26
|
os (0.9.6)
|
34
27
|
pry (0.10.3)
|
35
28
|
coderay (~> 1.1.0)
|
@@ -51,10 +44,6 @@ GEM
|
|
51
44
|
pry-rescue
|
52
45
|
pry-stack_explorer
|
53
46
|
rake (10.5.0)
|
54
|
-
rest-client (1.8.0)
|
55
|
-
http-cookie (>= 1.0.2, < 2.0)
|
56
|
-
mime-types (>= 1.16, < 3.0)
|
57
|
-
netrc (~> 0.7)
|
58
47
|
simplecov (0.11.2)
|
59
48
|
docile (~> 1.1.0)
|
60
49
|
json (~> 1.8)
|
@@ -65,9 +54,6 @@ GEM
|
|
65
54
|
tins (~> 1.0)
|
66
55
|
thor (0.19.1)
|
67
56
|
tins (1.6.0)
|
68
|
-
unf (0.1.4)
|
69
|
-
unf_ext
|
70
|
-
unf_ext (0.0.7.2)
|
71
57
|
|
72
58
|
PLATFORMS
|
73
59
|
ruby
|
data/README.md
CHANGED
@@ -1,4 +1,47 @@
|
|
1
|
+
[](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
|
2
|
+
[](https://codeclimate.com/github/hopsoft/kvn)
|
3
|
+
[](https://gemnasium.com/hopsoft/kvn)
|
4
|
+
[](https://travis-ci.org/hopsoft/kvn)
|
5
|
+
[](https://coveralls.io/r/hopsoft/kvn?branch=master)
|
6
|
+
[](http://rubygems.org/gems/kvn)
|
7
|
+
|
1
8
|
# KVN (kevin)
|
2
9
|
|
3
|
-
|
10
|
+
## Key/Value Notation
|
11
|
+
|
12
|
+
Similar to JSON but more limited in scope.
|
13
|
+
Can be used to represent basic key/value data structures as (human readable) strings.
|
14
|
+
|
15
|
+
Useful when working with limited storage options
|
16
|
+
to capture additional (human readable) data in a single field.
|
17
|
+
|
18
|
+
## Rules
|
19
|
+
|
20
|
+
* Data structures should be flat (i.e. 1 level deep, no nesting)
|
21
|
+
* Keys & values are limited to primitive types
|
22
|
+
|
23
|
+
* String
|
24
|
+
* Numeric
|
25
|
+
* Boolean
|
26
|
+
* Null
|
27
|
+
|
28
|
+
* Colons & semicolons are prohibited in keys & values
|
29
|
+
* Keys are sorted alphabetically
|
30
|
+
|
31
|
+
## Examples
|
32
|
+
|
33
|
+
### Convert a Hash to a KVN string
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
data = { d: "example with whitespace", a: true, c: "example", b: 1, e: nil }
|
37
|
+
Kvn::Converter.new(data).convert
|
38
|
+
# => "a:true; b:1; c:example; d:example with whitespace; e:null;"
|
39
|
+
```
|
40
|
+
|
41
|
+
### Parse a KVN string into a Hash
|
4
42
|
|
43
|
+
```ruby
|
44
|
+
value = "a:true; b:1; c:example; d:example with whitespace; e:null;"
|
45
|
+
Kvn::Parser.new(value).parse
|
46
|
+
# => {"a"=>true, "b"=>1, "c"=>"example", "d"=>"example with whitespace", "e"=>nil}
|
47
|
+
```
|
data/lib/kvn.rb
CHANGED
@@ -1,34 +1,21 @@
|
|
1
1
|
require "kvn/version"
|
2
|
-
require "kvn/
|
2
|
+
require "kvn/unsupported_hash_error"
|
3
|
+
require "kvn/value_lexer"
|
3
4
|
require "kvn/lexer"
|
5
|
+
require "kvn/converter"
|
4
6
|
require "kvn/parser"
|
5
7
|
|
6
8
|
module Kvn
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
value = standardize(value)
|
20
|
-
semicolon_count = value.scan(";").size
|
21
|
-
colon_count = value.scan(":").size
|
22
|
-
return false unless semicolon_count > 0
|
23
|
-
return false unless colon_count > 0
|
24
|
-
return false unless semicolon_count == colon_count
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def standardize(value)
|
30
|
-
value.to_s.strip
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
9
|
+
SUPPORTED_VALUE_TYPES = [
|
10
|
+
NilClass,
|
11
|
+
TrueClass,
|
12
|
+
FalseClass,
|
13
|
+
Symbol,
|
14
|
+
String,
|
15
|
+
Integer,
|
16
|
+
Fixnum,
|
17
|
+
Bignum,
|
18
|
+
Float,
|
19
|
+
Rational
|
20
|
+
]
|
34
21
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Kvn
|
2
|
+
class Converter
|
3
|
+
attr_reader :value
|
4
|
+
|
5
|
+
def initialize(value)
|
6
|
+
@value = (value ||= {}).to_h rescue {}
|
7
|
+
|
8
|
+
if invalid_values_present?
|
9
|
+
message = "All values must be a supported type! #{Kvn::SUPPORTED_VALUE_TYPES.join ", "}"
|
10
|
+
raise Kvn::UnsupportedHashError.new(message)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def convert
|
15
|
+
value.keys.sort.each_with_object([]) do |key, memo|
|
16
|
+
v = value[key]
|
17
|
+
v = "null" if v.nil?
|
18
|
+
next if v.to_s.strip.empty?
|
19
|
+
memo << "#{key}:#{v};"
|
20
|
+
end.join(" ")
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def standardize_value(value)
|
26
|
+
value.to_s.strip
|
27
|
+
end
|
28
|
+
|
29
|
+
def value_types
|
30
|
+
value.values.map(&:class).uniq
|
31
|
+
end
|
32
|
+
|
33
|
+
def invalid_values_present?
|
34
|
+
!(value_types - Kvn::SUPPORTED_VALUE_TYPES).empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/kvn/lexer.rb
CHANGED
@@ -9,14 +9,14 @@ module Kvn
|
|
9
9
|
:PARTDELIM
|
10
10
|
)
|
11
11
|
|
12
|
-
rule :KEY,
|
13
|
-
rule :VALUE, /(\
|
12
|
+
rule :KEY, /\w+(?=:)/
|
13
|
+
rule :VALUE, /[\w+(\s|\.)]+(?=;)/
|
14
14
|
rule :PAIRDELIM, /;\s*/
|
15
15
|
rule :PARTDELIM, /:/
|
16
16
|
|
17
17
|
error do |lexer, token|
|
18
|
-
message = "Illegal character in KVN string! #{token.line}:#{token.column}
|
19
|
-
raise
|
18
|
+
message = "Illegal character in KVN string! #{token.line}:#{token.column} <#{token.value}>"
|
19
|
+
raise SyntaxError.new(message)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
data/lib/kvn/parser.rb
CHANGED
@@ -1,28 +1,56 @@
|
|
1
1
|
module Kvn
|
2
2
|
class Parser
|
3
|
+
attr_reader :value
|
3
4
|
|
4
|
-
def
|
5
|
-
|
5
|
+
def initialize(value)
|
6
|
+
@value = value.to_s.strip
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse
|
6
10
|
lexer = Kvn::Lexer.new
|
7
|
-
output = lexer.lex(
|
11
|
+
output = lexer.lex(value)
|
12
|
+
{}.tap do |parsed|
|
13
|
+
begin
|
14
|
+
key = nil
|
15
|
+
key_found = false
|
16
|
+
value_found = false
|
17
|
+
while output.peek
|
18
|
+
token = output.next
|
19
|
+
if token.name == :KEY
|
20
|
+
key = token.value
|
21
|
+
key_found = true
|
22
|
+
value_found = false
|
23
|
+
end
|
24
|
+
|
25
|
+
if token.name == :VALUE
|
26
|
+
raise SyntaxError.new("Empty key detected for value! <#{token.value}>") unless key_found
|
27
|
+
parsed[key] = parse_value(token.value)
|
28
|
+
value_found = true
|
29
|
+
key_found = false
|
30
|
+
end
|
8
31
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
parsed[key] = token.value if token.name == :VALUE
|
32
|
+
if token.name == :PAIRDELIM && !value_found
|
33
|
+
raise SyntaxError.new("Empty value detected for key! <#{key}>")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
rescue StopIteration
|
15
37
|
end
|
16
|
-
rescue StopIteration
|
17
38
|
end
|
18
|
-
|
19
|
-
parsed
|
20
39
|
end
|
21
40
|
|
22
41
|
private
|
23
42
|
|
24
|
-
def
|
25
|
-
|
43
|
+
def parse_value(value)
|
44
|
+
lexer = Kvn::ValueLexer.new
|
45
|
+
token = lexer.lex(value).next
|
46
|
+
case token.name
|
47
|
+
when :NIL then value = nil
|
48
|
+
when :TRUE then value = true
|
49
|
+
when :FALSE then value = false
|
50
|
+
when :FLOAT then value = value.to_f
|
51
|
+
when :INTEGER then value = value.to_i
|
52
|
+
else value.to_s
|
53
|
+
end
|
26
54
|
end
|
27
55
|
|
28
56
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "lex"
|
2
|
+
|
3
|
+
module Kvn
|
4
|
+
class ValueLexer < Lex::Lexer
|
5
|
+
tokens(
|
6
|
+
:NIL,
|
7
|
+
:TRUE,
|
8
|
+
:FALSE,
|
9
|
+
:FLOAT,
|
10
|
+
:INTEGER,
|
11
|
+
:STRING
|
12
|
+
)
|
13
|
+
|
14
|
+
rule :NIL, /null/
|
15
|
+
rule :TRUE, /true/
|
16
|
+
rule :FALSE, /false/
|
17
|
+
rule :FLOAT, /\d+\.\d+/
|
18
|
+
rule :INTEGER, /\d+/
|
19
|
+
rule :STRING, /.*/
|
20
|
+
end
|
21
|
+
end
|
data/lib/kvn/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kvn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Hopkins
|
@@ -93,9 +93,11 @@ files:
|
|
93
93
|
- README.md
|
94
94
|
- Rakefile
|
95
95
|
- lib/kvn.rb
|
96
|
-
- lib/kvn/
|
96
|
+
- lib/kvn/converter.rb
|
97
97
|
- lib/kvn/lexer.rb
|
98
98
|
- lib/kvn/parser.rb
|
99
|
+
- lib/kvn/unsupported_hash_error.rb
|
100
|
+
- lib/kvn/value_lexer.rb
|
99
101
|
- lib/kvn/version.rb
|
100
102
|
homepage: https://github.com/hopsoft/kvn
|
101
103
|
licenses:
|
@@ -120,5 +122,5 @@ rubyforge_project:
|
|
120
122
|
rubygems_version: 2.5.1
|
121
123
|
signing_key:
|
122
124
|
specification_version: 4
|
123
|
-
summary: KVN
|
125
|
+
summary: KVN key/value notation converter & parser
|
124
126
|
test_files: []
|