toml-rb 0.3.6 → 0.3.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 763a2531f36107f17c09cf4b60399de4487fce09
4
- data.tar.gz: 891ced2d3c3dcd42baab838a0586c12b47976c2b
3
+ metadata.gz: 404c0a6fb64ad42ecd9de6e9569e072c5d2d68e8
4
+ data.tar.gz: 7ccfabbb8c4014867a8bc3d309363e6d1bb10eb6
5
5
  SHA512:
6
- metadata.gz: d8683b77c2b7dcdfc38c11af8d79ec376e6de7702cb977f3a53c0be0d2aa87151a1541eb54d3d91eef9730bcf8d011aee01820bf7185b6b4a3ba2705c94f53da
7
- data.tar.gz: fe95e0553af526da664b7e8de0581a8c9b9f4eb0e1c1c636743cab830b59a555222c16e3518558bd9efe6e76eed9c29695bdb5b44c31660921d7564eeaf6d39a
6
+ metadata.gz: afebe6d9de4b0eaaa913829c2fc35be18d2ac30339a6a158638612ed93f15196681624df0b164fd6baae3da5b7236fba1d6f46e79b7343bba1d7b6e51eb8db2f
7
+ data.tar.gz: 1c7b0380404eca6e933f45a28a7fa14c7bab52024879b4bf11c7c8f68bcb59f4c86edd35946575c960215e17d6af5fc85390228d3e409d64360680549574ef6d
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
- task :test do
2
- Dir['test/*_test.rb'].each { |file| load file }
3
- end
1
+ require 'rake/testtask'
4
2
 
3
+ Rake::TestTask.new do |t|
4
+ t.pattern = 'test/*_test.rb'
5
+ end
5
6
  task default: :test
data/init.rb CHANGED
@@ -2,6 +2,7 @@ require 'citrus'
2
2
 
3
3
  ROOT = File.dirname(File.expand_path(__FILE__))
4
4
 
5
+ require "#{ROOT}/lib/toml/errors"
5
6
  require "#{ROOT}/lib/toml/string"
6
7
  require "#{ROOT}/lib/toml/table_array"
7
8
  require "#{ROOT}/lib/toml/inline_table"
@@ -0,0 +1,17 @@
1
+ module TOML
2
+ # Parent class for all TOML errors
3
+ Error = Class.new(StandardError)
4
+
5
+ # Error related to parsing.
6
+ ParseError = Class.new(Error)
7
+
8
+ # Overwrite error
9
+ class ValueOverwriteError < Error
10
+ attr_accessor :key
11
+
12
+ def initialize(key)
13
+ self.key = key
14
+ super "Key #{key.inspect} is defined more than once"
15
+ end
16
+ end
17
+ end
@@ -7,11 +7,11 @@ grammar TOML::Document
7
7
  end
8
8
 
9
9
  rule table_array
10
- (space? '[[' (space? key space? "."?)+ ']]' space? comment?) <TOML::TableArrayParser>
10
+ (space? '[[' ((key "."?)+|'"'(space? key space? "."?)+'"') ']]' space? comment?) <TOML::TableArrayParser>
11
11
  end
12
12
 
13
13
  rule keygroup
14
- (space? '[' (space? key space? "."?)+ ']' space? comment?) <TOML::KeygroupParser>
14
+ (space? '[' ((key "."?)+|'"'(space? key space? "."?)+'"') ']' space? comment?) <TOML::KeygroupParser>
15
15
  end
16
16
 
17
17
  rule keyvalue
@@ -22,11 +22,11 @@ grammar TOML::Primitive
22
22
  end
23
23
 
24
24
  rule multiline_string
25
- ('"""' line_break* text:~'"""' '"""' space) <TOML::MultilineString>
25
+ ('"""' line_break* (text:~'"""'|'') '"""' space) <TOML::MultilineString>
26
26
  end
27
27
 
28
28
  rule multiline_literal
29
- ("'''" line_break* text:~"'''" "'''" space) <TOML::MultilineLiteral>
29
+ ("'''" line_break* (text:~"'''"|'') "'''" space) <TOML::MultilineLiteral>
30
30
  end
31
31
 
32
32
  ##
@@ -4,27 +4,32 @@ module TOML
4
4
  @nested_keys = nested_keys
5
5
  end
6
6
 
7
- def navigate_keys(hash, symbolize_keys = false)
8
- last_index = @nested_keys.length - 1
9
- @nested_keys.each_with_index do |key, i|
7
+ def navigate_keys(hash, visited_keys, symbolize_keys = false)
8
+ ensure_key_not_defined(visited_keys)
9
+ @nested_keys.each do |key|
10
10
  key = symbolize_keys ? key.to_sym : key
11
- # do not allow to define more than once just the last key
12
- if i == last_index && hash.key?(key)
13
- fail ValueOverwriteError.new(key)
14
- end
15
11
  hash[key] = {} unless hash.key?(key)
16
12
  element = hash[key]
17
13
  hash = element.is_a?(Array) ? element.last : element
18
14
  # check that key has not been defined before as a scalar value
19
15
  fail ValueOverwriteError.new(key) unless hash.is_a?(Hash)
20
16
  end
21
-
22
17
  hash
23
18
  end
24
19
 
20
+ # Fail if the key was already defined with a ValueOverwriteError
21
+ def ensure_key_not_defined(visited_keys)
22
+ fail ValueOverwriteError.new(full_key) if visited_keys.include?(full_key)
23
+ visited_keys << full_key
24
+ end
25
+
25
26
  def accept_visitor(parser)
26
27
  parser.visit_keygroup self
27
28
  end
29
+
30
+ def full_key
31
+ @nested_keys.join('.')
32
+ end
28
33
  end
29
34
  # Used in document.citrus
30
35
  module KeygroupParser
@@ -1,13 +1,4 @@
1
1
  module TOML
2
- class ValueOverwriteError < StandardError
3
- attr_accessor :key
4
-
5
- def initialize(key)
6
- self.key = key
7
- super "Key #{key.inspect} is defined more than once"
8
- end
9
- end
10
-
11
2
  class Keyvalue
12
3
  attr_reader :value, :symbolize_keys
13
4
 
@@ -1,11 +1,10 @@
1
1
  module TOML
2
- class ParseError < StandardError; end
3
-
4
2
  class Parser
5
3
  attr_reader :hash
6
4
 
7
5
  def initialize(content, options = {})
8
6
  @hash = {}
7
+ @visited_keys = Set.new
9
8
  @current = @hash
10
9
  @symbolize_keys = options[:symbolize_keys]
11
10
 
@@ -13,7 +12,7 @@ module TOML
13
12
  parsed = TOML::Document.parse(content)
14
13
  parsed.matches.map(&:value).compact.each { |m| m.accept_visitor(self) }
15
14
  rescue Citrus::ParseError => e
16
- raise ParseError.new(e.message)
15
+ raise TOML::ParseError.new(e.message)
17
16
  end
18
17
  end
19
18
 
@@ -24,7 +23,7 @@ module TOML
24
23
  end
25
24
 
26
25
  def visit_keygroup(keygroup)
27
- @current = keygroup.navigate_keys @hash, @symbolize_keys
26
+ @current = keygroup.navigate_keys @hash, @visited_keys, @symbolize_keys
28
27
  end
29
28
 
30
29
  def visit_keyvalue(keyvalue)
@@ -7,13 +7,29 @@ module TOML
7
7
  aux[1...-1]
8
8
  end
9
9
 
10
- def self.transform_escaped_chars(str)
10
+ # Replace the unicode escaped characters with the corresponding character
11
+ # e.g. \u03B4 => ?
12
+ def self.decode_unicode(str)
13
+ str.gsub(/([^\\](?:\\\\)*\\u[\da-f]{4})/i) do |m|
14
+ m[0...-6] + [m[-4..-1].to_i(16)].pack('U')
15
+ end
16
+ end
17
+
18
+ # Replace special characters such as line feed and tabs.
19
+ def self.decode_special_char(str)
11
20
  str.gsub(/\\0/, "\0")
12
21
  .gsub(/\\t/, "\t")
22
+ .gsub(/\\b/, "\b")
23
+ .gsub(/\\f/, "\f")
13
24
  .gsub(/\\n/, "\n")
14
25
  .gsub(/\\\"/, '"')
15
26
  .gsub(/\\r/, "\r")
16
- .gsub(/\\\\/, '\\')
27
+ end
28
+
29
+ def self.transform_escaped_chars(str)
30
+ str = decode_special_char(str)
31
+ str = decode_unicode(str)
32
+ str.gsub(/\\\\/, '\\').encode('utf-8')
17
33
  end
18
34
  end
19
35
 
@@ -25,6 +41,7 @@ module TOML
25
41
 
26
42
  module MultilineString
27
43
  def value
44
+ return '' if captures[:text].empty?
28
45
  aux = captures[:text].first.value
29
46
 
30
47
  # Remove spaces on multilined Singleline strings
@@ -36,6 +53,7 @@ module TOML
36
53
 
37
54
  module MultilineLiteral
38
55
  def value
56
+ return '' if captures[:text].empty?
39
57
  aux = captures[:text].first.value
40
58
 
41
59
  aux.gsub(/\\\r?\n[\n\t\r ]*/, '')
@@ -21,6 +21,10 @@ module TOML
21
21
  end
22
22
 
23
23
  # Define Table Array
24
+ if hash[last_key].is_a? Hash
25
+ fail TOML::ParseError,
26
+ "#{last_key} was defined as hash but is now redefined as a table!"
27
+ end
24
28
  hash[last_key] = [] unless hash[last_key]
25
29
  hash[last_key] << {}
26
30
 
@@ -1,6 +1,6 @@
1
1
  require_relative 'helper'
2
2
 
3
- class DumperTest < Test::Unit::TestCase
3
+ class DumperTest < Minitest::Test
4
4
  def test_dump_empty
5
5
  dumped = TOML.dump({})
6
6
  assert_equal('', dumped)
@@ -1,13 +1,13 @@
1
1
  require_relative 'helper'
2
2
 
3
- class ErrorsTest < Test::Unit::TestCase
3
+ class ErrorsTest < Minitest::Test
4
4
  def test_text_after_keygroup
5
5
  str = "[error] if you didn't catch this, your parser is broken"
6
6
  assert_raises(TOML::ParseError) { TOML.parse(str) }
7
7
  end
8
8
 
9
9
  def test_text_after_string
10
- str = 'string = "Anything other than tabs, spaces and newline after a '
10
+ str = 'string = "Anything other than tabs, spaces and newline after a '
11
11
  str += 'keygroup or key value pair has ended should produce an error '
12
12
  str += 'unless it is a comment" like this'
13
13
 
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require_relative 'helper'
3
3
 
4
- class GrammarTest < Test::Unit::TestCase
4
+ class GrammarTest < Minitest::Test
5
5
  def test_comment
6
6
  match = TOML::Document.parse(' # A comment', root: :comment)
7
7
  assert_equal(nil, match.value)
@@ -30,9 +30,13 @@ class GrammarTest < Test::Unit::TestCase
30
30
  assert_equal(%w(owner.emancu),
31
31
  match.value.instance_variable_get('@nested_keys'))
32
32
 
33
- match = TOML::Document.parse('[ owner . emancu ]', root: :keygroup)
34
- assert_equal(%w(owner emancu),
33
+ match = TOML::Document.parse('["first key"."second key"]', root: :keygroup)
34
+ assert_equal(['first key', 'second key'],
35
35
  match.value.instance_variable_get('@nested_keys'))
36
+
37
+ assert_raises Citrus::ParseError do
38
+ TOML::Document.parse('[ owner . emancu ]', root: :keygroup)
39
+ end
36
40
  end
37
41
 
38
42
  def test_keyvalue
@@ -64,6 +68,13 @@ class GrammarTest < Test::Unit::TestCase
64
68
  assert_equal "One Two", match.value
65
69
  end
66
70
 
71
+ def test_empty_multiline_string
72
+ to_parse = '""""""'
73
+
74
+ match = TOML::Document.parse(to_parse, root: :multiline_string)
75
+ assert_equal '', match.value
76
+ end
77
+
67
78
  def test_special_characters
68
79
  match = TOML::Document.parse('"\0 \" \t \n \r"', root: :string)
69
80
  assert_equal("\0 \" \t \n \r", match.value)
@@ -146,7 +157,7 @@ class GrammarTest < Test::Unit::TestCase
146
157
  assert_equal([%w(hey TOML), [2, 4]], match.value)
147
158
 
148
159
  match = TOML::Document.parse('[ { one = 1 }, { two = 2, three = 3} ]',
149
- root: :inline_table_array)
160
+ root: :inline_table_array)
150
161
  assert_equal([{ 'one' => 1 }, { 'two' => 2, 'three' => 3 }], match.value)
151
162
  end
152
163
 
@@ -1,2 +1,2 @@
1
- require 'test/unit'
1
+ require 'minitest/autorun'
2
2
  require_relative '../lib/toml'
@@ -1,7 +1,8 @@
1
1
  require_relative 'helper'
2
2
  require_relative 'toml_examples'
3
+ require 'json'
3
4
 
4
- class TomlTest < Test::Unit::TestCase
5
+ class TomlTest < Minitest::Test
5
6
  def test_file_v_0_4_0
6
7
  path = File.join(File.dirname(__FILE__), 'example-v0.4.0.toml')
7
8
  parsed = TOML.load_file(path)
@@ -84,4 +85,34 @@ class TomlTest < Test::Unit::TestCase
84
85
  parsed = TOML.parse("hello = 'world'\r\nline_break = true")
85
86
  assert_equal({ 'hello' => 'world', 'line_break' => true }, parsed)
86
87
  end
88
+
89
+ def compare_toml_files(folder, file = nil, &block)
90
+ file ||= '*'
91
+ Dir["test/examples/#{folder}/#{file}.json"].each do |json_file|
92
+ toml_file = File.join(File.dirname(json_file),
93
+ File.basename(json_file, '.json')) + '.toml'
94
+ begin
95
+ toml = TOML.load_file(toml_file)
96
+ rescue TOML::Error => e
97
+ assert false, "Error: #{e} in #{toml_file}"
98
+ end
99
+ json = JSON.parse(File.read(json_file))
100
+ block.call(json, toml, toml_file)
101
+ end
102
+ end
103
+
104
+ def test_valid_cases
105
+ compare_toml_files 'valid' do |json, toml, file|
106
+ assert_equal json, toml, "In file '#{file}'"
107
+ end
108
+ end
109
+
110
+ def test_invalid_cases
111
+ file = '*'
112
+ Dir["test/examples/invalid/#{file}.toml"].each do |toml_file|
113
+ assert_raises(TOML::Error, "For file #{toml_file}") do
114
+ TOML.load_file(toml_file)
115
+ end
116
+ end
117
+ end
87
118
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'toml-rb'
3
- s.version = '0.3.6'
3
+ s.version = '0.3.7'
4
4
  s.date = Time.now.strftime('%Y-%m-%d')
5
5
  s.summary = 'TOML parser in ruby, for ruby.'
6
6
  s.description = 'A TOML parser using Citrus parsing library. '
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: 0.3.6
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emiliano Mancuso
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-05-22 00:00:00.000000000 Z
12
+ date: 2015-06-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: citrus
@@ -44,6 +44,7 @@ files:
44
44
  - init.rb
45
45
  - lib/toml.rb
46
46
  - lib/toml/dumper.rb
47
+ - lib/toml/errors.rb
47
48
  - lib/toml/grammars/array.citrus
48
49
  - lib/toml/grammars/document.citrus
49
50
  - lib/toml/grammars/helper.citrus