toml-rb 1.1.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,31 +1,39 @@
1
+ require_relative "inline_table"
2
+
1
3
  module TomlRB
2
4
  class Keyvalue
3
- attr_reader :value, :symbolize_keys
5
+ attr_reader :dotted_keys, :value, :symbolize_keys
4
6
 
5
- def initialize(key, value)
6
- @key = key
7
+ def initialize(dotted_keys, value)
8
+ @dotted_keys = dotted_keys
7
9
  @value = value
8
10
  @symbolize_keys = false
9
11
  end
10
12
 
11
- def assign(hash, symbolize_keys = false)
13
+ def assign(hash, fully_defined_keys, symbolize_keys = false)
12
14
  @symbolize_keys = symbolize_keys
13
- fail ValueOverwriteError.new(key) if hash.key?(key)
14
- hash[key] = visit_value @value
15
- end
16
-
17
- def visit_inline_table(inline_table)
18
- result = {}
19
-
20
- inline_table.value(@symbolize_keys).each do |k, v|
21
- result[key k] = visit_value v
15
+ dotted_keys_str = @dotted_keys.join(".")
16
+ keys = symbolize_keys ? @dotted_keys.map(&:to_sym) : @dotted_keys
17
+ update = keys.reverse.inject(visit_value @value) { |k1, k2| { k2 => k1 } }
18
+
19
+ if @value.is_a?(InlineTable)
20
+ fully_defined_keys << dotted_keys_str
21
+ hash.merge!(update) { |key, _, _| fail ValueOverwriteError.new(key) }
22
+ elsif fully_defined_keys.find{|k| update.dig(*k)}
23
+ hash.merge!(update) { |key, _, _| fail ValueOverwriteError.new(key) }
24
+ else
25
+ dotted_key_merge(hash, update)
22
26
  end
23
-
24
- result
25
27
  end
26
28
 
27
- def key(a_key = @key)
28
- symbolize_keys ? a_key.to_sym : a_key
29
+ def dotted_key_merge(hash, update)
30
+ hash.merge!(update) { |key, old, new|
31
+ if old.is_a?(Hash) && new.is_a?(Hash)
32
+ dotted_key_merge(old, new)
33
+ else
34
+ fail ValueOverwriteError.new(key)
35
+ end
36
+ }
29
37
  end
30
38
 
31
39
  def accept_visitor(parser)
@@ -5,6 +5,7 @@ module TomlRB
5
5
  def initialize(content, options = {})
6
6
  @hash = {}
7
7
  @visited_keys = []
8
+ @fully_defined_keys = []
8
9
  @current = @hash
9
10
  @symbolize_keys = options[:symbolize_keys]
10
11
 
@@ -19,18 +20,20 @@ module TomlRB
19
20
  # Read about the Visitor pattern
20
21
  # http://en.wikipedia.org/wiki/Visitor_pattern
21
22
  def visit_table_array(table_array)
23
+ @fully_defined_keys = []
22
24
  table_array_key = table_array.full_key
23
25
  @visited_keys.reject! { |k| k.start_with? table_array_key }
24
26
 
25
27
  @current = table_array.navigate_keys @hash, @symbolize_keys
26
28
  end
27
29
 
28
- def visit_keygroup(keygroup)
29
- @current = keygroup.navigate_keys @hash, @visited_keys, @symbolize_keys
30
+ def visit_table(table)
31
+ @fully_defined_keys = []
32
+ @current = table.navigate_keys @hash, @visited_keys, @symbolize_keys
30
33
  end
31
34
 
32
35
  def visit_keyvalue(keyvalue)
33
- keyvalue.assign @current, @symbolize_keys
36
+ keyvalue.assign @current, @fully_defined_keys, @symbolize_keys
34
37
  end
35
38
  end
36
39
  end
@@ -1,20 +1,21 @@
1
1
  module TomlRB
2
- class Keygroup
3
- def initialize(nested_keys)
4
- @nested_keys = nested_keys
2
+ class Table
3
+ def initialize(dotted_keys)
4
+ @dotted_keys = dotted_keys
5
5
  end
6
6
 
7
7
  def navigate_keys(hash, visited_keys, symbolize_keys = false)
8
8
  ensure_key_not_defined(visited_keys)
9
- @nested_keys.each do |key|
10
- key = symbolize_keys ? key.to_sym : key
11
- hash[key] = {} unless hash.key?(key)
12
- element = hash[key]
13
- hash = element.is_a?(Array) ? element.last : element
9
+ current = hash
10
+ keys = symbolize_keys ? @dotted_keys.map(&:to_sym) : @dotted_keys
11
+ keys.each do |key|
12
+ current[key] = {} unless current.key?(key)
13
+ element = current[key]
14
+ current = element.is_a?(Array) ? element.last : element
14
15
  # check that key has not been defined before as a scalar value
15
- fail ValueOverwriteError.new(key) unless hash.is_a?(Hash)
16
+ fail ValueOverwriteError.new(key) unless current.is_a?(Hash)
16
17
  end
17
- hash
18
+ current
18
19
  end
19
20
 
20
21
  # Fail if the key was already defined with a ValueOverwriteError
@@ -24,18 +25,18 @@ module TomlRB
24
25
  end
25
26
 
26
27
  def accept_visitor(parser)
27
- parser.visit_keygroup self
28
+ parser.visit_table self
28
29
  end
29
30
 
30
31
  def full_key
31
- @nested_keys.join('.')
32
+ @dotted_keys.join('.')
32
33
  end
33
34
  end
34
35
 
35
36
  # Used in document.citrus
36
- module KeygroupParser
37
+ module TableParser
37
38
  def value
38
- TomlRB::Keygroup.new(captures[:stripped_key].map(&:value))
39
+ TomlRB::Table.new(captures[:stripped_key].map(&:value).first)
39
40
  end
40
41
  end
41
42
  end
@@ -1,35 +1,35 @@
1
1
  module TomlRB
2
2
  class TableArray
3
- def initialize(nested_keys)
4
- @nested_keys = nested_keys
3
+ def initialize(dotted_keys)
4
+ @dotted_keys = dotted_keys
5
5
  end
6
6
 
7
7
  def navigate_keys(hash, symbolize_keys = false)
8
- last_key = @nested_keys.pop
9
- last_key = last_key.to_sym if symbolize_keys
8
+ current = hash
9
+ keys = symbolize_keys ? @dotted_keys.map(&:to_sym) : @dotted_keys
10
+ last_key = keys.pop
10
11
 
11
12
  # Go over the parent keys
12
- @nested_keys.each do |key|
13
- key = symbolize_keys ? key.to_sym : key
14
- hash[key] = {} unless hash[key]
13
+ keys.each do |key|
14
+ current[key] = {} unless current[key]
15
15
 
16
- if hash[key].is_a? Array
17
- hash[key] << {} if hash[key].empty?
18
- hash = hash[key].last
16
+ if current[key].is_a? Array
17
+ current[key] << {} if current[key].empty?
18
+ current = current[key].last
19
19
  else
20
- hash = hash[key]
20
+ current = current[key]
21
21
  end
22
22
  end
23
23
 
24
24
  # Define Table Array
25
- if hash[last_key].is_a? Hash
25
+ if current[last_key].is_a? Hash
26
26
  fail TomlRB::ParseError,
27
27
  "#{last_key} was defined as hash but is now redefined as a table!"
28
28
  end
29
- hash[last_key] = [] unless hash[last_key]
30
- hash[last_key] << {}
29
+ current[last_key] = [] unless current[last_key]
30
+ current[last_key] << {}
31
31
 
32
- hash[last_key].last
32
+ current[last_key].last
33
33
  end
34
34
 
35
35
  def accept_visitor(parser)
@@ -37,14 +37,14 @@ module TomlRB
37
37
  end
38
38
 
39
39
  def full_key
40
- @nested_keys.join('.')
40
+ @dotted_keys.join('.')
41
41
  end
42
42
  end
43
43
 
44
44
  # Used in document.citrus
45
45
  module TableArrayParser
46
46
  def value
47
- TomlRB::TableArray.new(captures[:stripped_key].map(&:value))
47
+ TomlRB::TableArray.new(captures[:stripped_key].map(&:value).first)
48
48
  end
49
49
  end
50
50
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toml-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emiliano Mancuso
@@ -9,26 +9,26 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-08-16 00:00:00.000000000 Z
12
+ date: 2019-10-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: citrus
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">"
19
19
  - !ruby/object:Gem::Version
20
20
  version: '3.0'
21
- - - ">"
21
+ - - "~>"
22
22
  - !ruby/object:Gem::Version
23
23
  version: '3.0'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
- - - "~>"
28
+ - - ">"
29
29
  - !ruby/object:Gem::Version
30
30
  version: '3.0'
31
- - - ">"
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '3.0'
34
34
  description: 'A Toml parser using Citrus parsing library. '
@@ -39,10 +39,11 @@ executables: []
39
39
  extensions: []
40
40
  extra_rdoc_files: []
41
41
  files:
42
+ - LICENSE
42
43
  - README.md
43
- - Rakefile
44
44
  - lib/toml-rb.rb
45
45
  - lib/toml-rb/array.rb
46
+ - lib/toml-rb/datetime.rb
46
47
  - lib/toml-rb/dumper.rb
47
48
  - lib/toml-rb/errors.rb
48
49
  - lib/toml-rb/grammars/array.citrus
@@ -50,22 +51,12 @@ files:
50
51
  - lib/toml-rb/grammars/helper.citrus
51
52
  - lib/toml-rb/grammars/primitive.citrus
52
53
  - lib/toml-rb/inline_table.rb
53
- - lib/toml-rb/keygroup.rb
54
54
  - lib/toml-rb/keyvalue.rb
55
55
  - lib/toml-rb/parser.rb
56
56
  - lib/toml-rb/string.rb
57
+ - lib/toml-rb/table.rb
57
58
  - lib/toml-rb/table_array.rb
58
- - test/dumper_test.rb
59
- - test/errors_test.rb
60
- - test/example-v0.4.0.toml
61
- - test/example.toml
62
- - test/grammar_test.rb
63
- - test/hard_example.toml
64
- - test/helper.rb
65
- - test/toml_examples.rb
66
- - test/toml_test.rb
67
- - toml-rb.gemspec
68
- homepage: http://github.com/emancu/toml-rb
59
+ homepage: https://github.com/emancu/toml-rb
69
60
  licenses:
70
61
  - MIT
71
62
  metadata: {}
@@ -77,15 +68,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
77
68
  requirements:
78
69
  - - ">="
79
70
  - !ruby/object:Gem::Version
80
- version: '1.9'
71
+ version: '2.3'
81
72
  required_rubygems_version: !ruby/object:Gem::Requirement
82
73
  requirements:
83
74
  - - ">="
84
75
  - !ruby/object:Gem::Version
85
76
  version: '0'
86
77
  requirements: []
87
- rubyforge_project:
88
- rubygems_version: 2.6.14.1
78
+ rubygems_version: 3.0.3
89
79
  signing_key:
90
80
  specification_version: 4
91
81
  summary: Toml parser in ruby, for ruby.
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require 'rake/testtask'
2
-
3
- Rake::TestTask.new do |t|
4
- t.pattern = 'test/*_test.rb'
5
- end
6
- task default: :test
@@ -1,94 +0,0 @@
1
- require_relative 'helper'
2
-
3
- class DumperTest < Minitest::Test
4
- def test_dump_empty
5
- dumped = TomlRB.dump({})
6
- assert_equal('', dumped)
7
- end
8
-
9
- def test_dump_types
10
- dumped = TomlRB.dump(string: 'TomlRB "dump"')
11
- assert_equal("string = \"TomlRB \\\"dump\\\"\"\n", dumped)
12
-
13
- dumped = TomlRB.dump(float: -13.24)
14
- assert_equal("float = -13.24\n", dumped)
15
-
16
- dumped = TomlRB.dump(int: 1234)
17
- assert_equal("int = 1234\n", dumped)
18
-
19
- dumped = TomlRB.dump(true: true)
20
- assert_equal("true = true\n", dumped)
21
-
22
- dumped = TomlRB.dump(false: false)
23
- assert_equal("false = false\n", dumped)
24
-
25
- dumped = TomlRB.dump(array: [1, 2, 3])
26
- assert_equal("array = [1, 2, 3]\n", dumped)
27
-
28
- dumped = TomlRB.dump(array: [[1, 2], %w(weird one)])
29
- assert_equal("array = [[1, 2], [\"weird\", \"one\"]]\n", dumped)
30
-
31
- dumped = TomlRB.dump(datetime: Time.utc(1986, 8, 28, 15, 15))
32
- assert_equal("datetime = 1986-08-28T15:15:00Z\n", dumped)
33
- end
34
-
35
- def test_dump_nested_attributes
36
- hash = { nested: { hash: { deep: true } } }
37
- dumped = TomlRB.dump(hash)
38
- assert_equal("[nested.hash]\ndeep = true\n", dumped)
39
-
40
- hash[:nested].merge!(other: 12)
41
- dumped = TomlRB.dump(hash)
42
- assert_equal("[nested]\nother = 12\n[nested.hash]\ndeep = true\n", dumped)
43
-
44
- hash[:nested].merge!(nest: { again: 'it never ends' })
45
- dumped = TomlRB.dump(hash)
46
- toml = <<-EOS.gsub(/^ {6}/, '')
47
- [nested]
48
- other = 12
49
- [nested.hash]
50
- deep = true
51
- [nested.nest]
52
- again = "it never ends"
53
- EOS
54
-
55
- assert_equal(toml, dumped)
56
-
57
- hash = { non: { 'bare."keys"' => { "works" => true } } }
58
- dumped = TomlRB.dump(hash)
59
- assert_equal("[non.\"bare.\\\"keys\\\"\"]\nworks = true\n", dumped)
60
-
61
- hash = { hola: [{ chau: 4 }, { chau: 3 }] }
62
- dumped = TomlRB.dump(hash)
63
- assert_equal("[[hola]]\nchau = 4\n[[hola]]\nchau = 3\n", dumped)
64
- end
65
-
66
- def test_print_empty_tables
67
- hash = { plugins: { cpu: { foo: "bar", baz: 1234 }, disk: {}, io: {} } }
68
- dumped = TomlRB.dump(hash)
69
- toml = <<-EOS.gsub(/^ {6}/, '')
70
- [plugins.cpu]
71
- baz = 1234
72
- foo = "bar"
73
- [plugins.disk]
74
- [plugins.io]
75
- EOS
76
-
77
- assert_equal toml, dumped
78
- end
79
-
80
- def test_dump_array_tables
81
- hash = { fruit: [{ physical: { color: "red" } }, { physical: { color: "blue" } }] }
82
- dumped = TomlRB.dump(hash)
83
- toml = <<-EOS.gsub(/^ {6}/, '')
84
- [[fruit]]
85
- [fruit.physical]
86
- color = "red"
87
- [[fruit]]
88
- [fruit.physical]
89
- color = "blue"
90
- EOS
91
-
92
- assert_equal toml, dumped
93
- end
94
- end
@@ -1,88 +0,0 @@
1
- require_relative 'helper'
2
-
3
- class ErrorsTest < Minitest::Test
4
- def test_text_after_keygroup
5
- str = "[error] if you didn't catch this, your parser is broken"
6
- assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
7
- end
8
-
9
- def test_text_after_string
10
- str = 'string = "Anything other than tabs, spaces and newline after a '
11
- str += 'keygroup or key value pair has ended should produce an error '
12
- str += 'unless it is a comment" like this'
13
-
14
- assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
15
- end
16
-
17
- def test_multiline_array_bad_string
18
- str = <<-EOS
19
- array = [
20
- "This might most likely happen in multiline arrays",
21
- Like here,
22
- "or here,
23
- and here"
24
- ] End of array comment, forgot the #
25
- EOS
26
-
27
- assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
28
- end
29
-
30
- def test_multiline_array_string_not_ended
31
- str = <<-EOS
32
- array = [
33
- "This might most likely happen in multiline arrays",
34
- "or here,
35
- and here"
36
- ] End of array comment, forgot the #
37
- EOS
38
-
39
- assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
40
- end
41
-
42
- def test_text_after_multiline_array
43
- str = <<-EOS
44
- array = [
45
- "This might most likely happen in multiline arrays",
46
- "or here",
47
- "and here"
48
- ] End of array comment, forgot the #
49
- EOS
50
-
51
- assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
52
- end
53
-
54
- def test_text_after_number
55
- str = 'number = 3.14 pi <--again forgot the #'
56
- assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
57
- end
58
-
59
- def test_value_overwrite
60
- str = "a = 1\na = 2"
61
- e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
62
- assert_equal "Key \"a\" is defined more than once", e.message
63
- assert_equal "a", e.key
64
-
65
- str = "a = false\na = true"
66
- assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
67
- end
68
-
69
- def test_table_overwrite
70
- str = "[a]\nb=1\n[a]\nc=2"
71
- e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
72
- assert_equal "Key \"a\" is defined more than once", e.message
73
-
74
- str = "[a]\nb=1\n[a]\nb=1"
75
- e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
76
- assert_equal "Key \"a\" is defined more than once", e.message
77
- end
78
-
79
- def test_value_overwrite_with_table
80
- str = "[a]\nb=1\n[a.b]\nc=2"
81
- e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
82
- assert_equal "Key \"b\" is defined more than once", e.message
83
-
84
- str = "[a]\nb=1\n[a.b.c]\nd=3"
85
- e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
86
- assert_equal "Key \"b\" is defined more than once", e.message
87
- end
88
- end