toml-rb 1.1.2 → 2.0.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.
@@ -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