toml-rb 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
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