toml 0.0.1 → 0.0.2

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.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in toml.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'minitest'
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ toml (0.0.1)
5
+ parslet
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ blankslate (2.1.2.4)
11
+ minitest (4.6.1)
12
+ parslet (1.5.0)
13
+ blankslate (~> 2.0)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ minitest
20
+ toml!
data/README.md CHANGED
@@ -1,69 +1,35 @@
1
- RakeGem
2
- =======
1
+ # TOML
3
2
 
4
- # DESCRIPTION
3
+ A sane configuration format from @mojombo. More information here: https://github.com/mojombo/toml
5
4
 
6
- Ever wanted to manage your RubyGem in a sane way without having to resort to
7
- external dependencies like Jeweler or Hoe? Ever thought that Rake and a hand
8
- crafted gemspec should be enough to deal with these problems? If so, then
9
- RakeGem is here to make your life awesome!
5
+ ## Usage
10
6
 
11
- RakeGem is not a library. It is just a few simple file templates that you can
12
- copy into your project and easily customize to match your specific needs. It
13
- ships with a few Rake tasks to help you keep your gemspec up-to-date, build
14
- a gem, and release your library and gem to the world.
7
+ It's simple, really.
15
8
 
16
- RakeGem assumes you are using Git. This makes the Rake tasks easy to write. If
17
- you are using something else, you should be able to get RakeGem up and running
18
- with your system without too much editing.
9
+ ```ruby
10
+ content = <<-TOML
19
11
 
20
- The RakeGem tasks were inspired by the
21
- [Sinatra](http://github.com/sinatra/sinatra) project.
12
+ # Hello, this is an example.
13
+ [things]
14
+ other = "things"
15
+ what = 900000
22
16
 
23
- # INSTALLATION
17
+ TOML
24
18
 
25
- Take a look at `Rakefile` and `NAME.gemspec`. For new projects, you can start
26
- with these files and edit a few lines to make them fit into your library. If
27
- you have an existing project, you'll probably want to take the RakeGem
28
- versions and copy any custom stuff from your existing Rakefile and gemspec
29
- into them. As long as you're careful, the rake tasks should keep working.
19
+ parser = TOML::Parser.new(content).parsed
20
+ # => { "things" => { "other" => "things", "what" => 900000 } }
21
+ ```
30
22
 
31
- # ASSUMPTIONS
23
+ You can also use the same API as `YAML` if you'd like:
32
24
 
33
- RakeGem makes a few assumptions. You will either need to satisfy these
34
- assumptions or modify the rake tasks to work with your setup.
25
+ ```ruby
26
+ TOML.load("thing = 9")
27
+ # => {"thing" => 9}
35
28
 
36
- You should have a file named `lib/NAME.rb` (where NAME is the name of your
37
- library) that contains a version line. It should look something like this:
29
+ TOML.load_file("my_file.toml")
30
+ # => {"whatever" => "keys"}
31
+ ```
38
32
 
39
- module NAME
40
- VERSION = '0.1.0'
41
- end
33
+ ## Contributors
42
34
 
43
- It is important that you use the constant `VERSION` and that it appear on a
44
- line by itself.
45
-
46
- # UPDATING THE VERSION
47
-
48
- In order to make a new release, you'll want to update the version. With
49
- RakeGem, you only need to do that in the `lib/NAME.rb` file. Everything else
50
- will use this find the canonical version of the library.
51
-
52
- # TASKS
53
-
54
- RakeGem provides three rake tasks:
55
-
56
- `rake gemspec` will update your gemspec with the latest version (taken from
57
- the `lib/NAME.rb` file) and file list (as reported by `git ls-files`).
58
-
59
- `rake build` will update your gemspec, build your gemspec into a gem, and
60
- place it in the `pkg` directory.
61
-
62
- `rake release` will update your gemspec, build your gem, make a commit with
63
- the message `Release 0.1.0` (with the correct version, obviously), tag the
64
- commit with `v0.1.0` (again with the correct version), and push the `master`
65
- branch and new tag to `origin`.
66
-
67
- Keep in mind that these are just simple Rake tasks and you can edit them
68
- however you please. Don't want to auto-commit or auto-push? Just delete those
69
- lines. You can bend RakeGem to your own needs. That's the whole point!
35
+ Written by Jeremy McAnally (@jm) and Dirk Gadsden (@dirk) based on TOML from Tom Preston-Werner (@mojombo).
data/lib/toml.rb CHANGED
@@ -1,8 +1,22 @@
1
1
  $:.unshift(File.dirname(__FILE__))
2
2
 
3
3
  require 'time'
4
+ require 'parslet'
5
+
6
+ require 'toml/key'
7
+ require 'toml/key_group'
8
+ require 'toml/parslet'
9
+ require 'toml/transformer'
4
10
  require 'toml/parser'
5
11
 
6
12
  module TOML
7
- VERSION = '0.0.1'
13
+ VERSION = '0.0.2'
14
+
15
+ def self.load(content)
16
+ Parser.new(content).parsed
17
+ end
18
+
19
+ def self.load_file(path)
20
+ Parser.new(File.read(path)).parsed
21
+ end
8
22
  end
data/lib/toml/key.rb ADDED
@@ -0,0 +1,9 @@
1
+ module TOML
2
+ class Key
3
+ attr_reader :key, :value
4
+ def initialize(key, value)
5
+ @key = key
6
+ @value = value
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module TOML
2
+ class KeyGroup
3
+ attr_reader :keys
4
+
5
+ def initialize(keys)
6
+ @keys = keys
7
+ end
8
+ end
9
+ end
data/lib/toml/parser.rb CHANGED
@@ -1,67 +1,40 @@
1
- module TOML
1
+ module TOML
2
2
  class Parser
3
3
  attr_reader :parsed
4
4
 
5
5
  def initialize(markup)
6
- lines = markup.split("\n").reject {|l| l.start_with?("#") }
6
+ # Make sure we have a newline on the end
7
+ markup += "\n" unless markup.end_with?("\n")
7
8
 
9
+ tree = Parslet.new.parse(markup)
10
+ parts = Transformer.new.apply(tree)
11
+
8
12
  @parsed = {}
9
- @current_key_group = ""
10
-
11
- lines.each do |line|
12
- if line.gsub(/\s/, '').empty?
13
- close_key_group
14
- elsif line =~ /^\s?\[(.*)\]/
15
- new_key_group($1)
16
- elsif line =~ /\s?(.*)=(.*)/
17
- add_key($1, $2)
13
+ @current = @parsed
14
+
15
+ parts.each do |part|
16
+ if part.is_a? Key
17
+ @current[part.key] = part.value
18
+ elsif part.is_a? KeyGroup
19
+ resolve_key_group(part)
18
20
  else
19
- raise "lmao i have no clue what you're doing: #{line}"
21
+ raise "Unrecognized part: #{part.inspect}"
20
22
  end
21
23
  end
22
24
  end
23
-
24
- def new_key_group(key_name)
25
- @current_key_group = key_name
26
- end
27
-
28
- def add_key(key, value)
29
- @parsed[@current_key_group] ||= {}
30
- @parsed[@current_key_group][key.strip] = coerce(strip_comments(value))
31
- end
32
-
33
- def strip_comments(text)
34
- text.split("#").first
35
- end
36
-
37
- def coerce(value)
38
- value = value.strip
39
- if value =~ /\[(.*)\]/
40
- # array
41
- array = $1.split(",").map {|s| s.strip.gsub(/\"(.*)\"/, '\1')}
42
- return array
43
- elsif value =~ /\"(.*)\"/
44
- # string
45
- return $1
46
- end
47
-
48
- begin
49
- time = Time.parse(value)
50
- return time
51
- rescue
52
- end
53
-
54
- begin
55
- int = Integer(value)
56
- return int
57
- rescue
25
+
26
+ def resolve_key_group(kg)
27
+ @current = @parsed
28
+
29
+ path = kg.keys.dup
30
+ while k = path.shift
31
+ if @current.has_key? k
32
+ # pass
33
+ else
34
+ @current[k] = {}
35
+ end
36
+ @current = @current[k]
58
37
  end
59
-
60
- raise "lol no clue what [#{value}] is"
61
- end
62
-
63
- def close_key_group
64
- @current_key_group = ""
65
38
  end
66
39
  end
67
- end
40
+ end
@@ -0,0 +1,67 @@
1
+ module TOML
2
+ class Parslet < ::Parslet::Parser
3
+ rule(:document) { (key_group | key_value | comment_line).repeat(0) }
4
+ root :document
5
+
6
+ rule(:value) {
7
+ array.as(:array) |
8
+ string |
9
+ datetime.as(:datetime) |
10
+ float.as(:float) |
11
+ integer.as(:integer) |
12
+ boolean
13
+ }
14
+
15
+ rule(:array) {
16
+ str("[") >> (
17
+ all_space >> value >>
18
+ (all_space >> str(",") >> all_space >> value).repeat(0) >>
19
+ all_space
20
+ ).maybe >> str("]")
21
+ }
22
+
23
+ rule(:key_value) { space >> key.as(:key) >> space >> str("=") >> space >> value >> space >> comment.maybe >> str("\n") >> all_space }
24
+ rule(:key_group) { space >> str("[") >> key_group_name.as(:key_group) >> str("]") >> space >> comment.maybe >> str("\n") >> all_space }
25
+
26
+ rule(:key) { match("[^. \t\\]]").repeat(1) }
27
+ rule(:key_group_name) { key.as(:key) >> (str(".") >> key.as(:key)).repeat(0) }
28
+
29
+ rule(:comment_line) { comment >> str("\n") >> all_space }
30
+ rule(:comment) { str("#") >> match("[^\n]").repeat(0) }
31
+
32
+ rule(:space) { match("[ \t]").repeat(0) }
33
+ rule(:all_space) { match("[ \t\r\n]").repeat(0) }
34
+
35
+ rule(:string) {
36
+ str('"') >> (
37
+ match("[^\"\\\\]") |
38
+ (str("\\") >> match("[0tnr\"\\\\]"))
39
+ ).repeat(0).as(:string) >> str('"')
40
+ }
41
+
42
+ rule(:sign) { str("-") }
43
+ rule(:integer) {
44
+ str("0") | (sign.maybe >> match("[1-9]") >> match("[0-9]").repeat(0))
45
+ }
46
+
47
+ rule(:float) {
48
+ sign.maybe >> match("[0-9]").repeat(1) >> str(".") >> match("[0-9]").repeat(1)
49
+ }
50
+
51
+ rule(:boolean) { str("true").as(:true) | str("false").as(:false) }
52
+
53
+ rule(:date) {
54
+ match("[0-9]").repeat(4,4) >> str("-") >>
55
+ match("[0-9]").repeat(2,2) >> str("-") >>
56
+ match("[0-9]").repeat(2,2)
57
+ }
58
+
59
+ rule(:time) {
60
+ match("[0-9]").repeat(2,2) >> str(":") >>
61
+ match("[0-9]").repeat(2,2) >> str(":") >>
62
+ match("[0-9]").repeat(2,2)
63
+ }
64
+
65
+ rule(:datetime) { date >> str("T") >> time >> str("Z") }
66
+ end
67
+ end
@@ -0,0 +1,74 @@
1
+ module TOML
2
+ class Transformer < ::Parslet::Transform
3
+ # Utility to properly handle escape sequences in parsed string.
4
+ def self.parse_string(val)
5
+ e = val.length
6
+ s = 0
7
+ o = []
8
+ while s < e
9
+ if val[s] == "\\"
10
+ s += 1
11
+ case val[s]
12
+ when "t"
13
+ o << "\t"
14
+ when "n"
15
+ o << "\n"
16
+ when "\\"
17
+ o << "\\"
18
+ when '"'
19
+ o << '"'
20
+ when "r"
21
+ o << "\r"
22
+ when "0"
23
+ o << "\0"
24
+ else
25
+ raise "Unexpected escape character: '\\#{val[s]}'"
26
+ end
27
+ else
28
+ o << val[s]
29
+ end
30
+ s += 1
31
+ end
32
+ o.join
33
+ end
34
+
35
+ # Clean up arrays
36
+ rule(:array => subtree(:ar)) { ar.is_a?(Array) ? ar : [ar] }
37
+
38
+ # Clean up simples (inside arrays)
39
+ rule(:integer => simple(:i)) { i.to_i }
40
+ rule(:float => simple(:f)) { f.to_f }
41
+ rule(:string => simple(:s)) {
42
+ Transformer.parse_string(s.to_s)
43
+ }
44
+ rule(:datetime => simple(:d)) { DateTime.iso8601(d) }
45
+ rule(:true => simple(:b)) { true }
46
+ rule(:false => simple(:b)) { false }
47
+
48
+ # TODO: Refactor to remove redundancy
49
+ rule(:key => simple(:k), :array => subtree(:ar)) { Key.new(k.to_s, ar) }
50
+ rule(:key => simple(:k), :integer => simple(:i)) { Key.new(k.to_s, i.to_i) }
51
+ rule(:key => simple(:k), :float => simple(:f)) { Key.new(k.to_s, f.to_f) }
52
+ rule(:key => simple(:k), :string => simple(:s)) {
53
+ Key.new(k.to_s, Transformer.parse_string(s.to_s))
54
+ }
55
+ rule(:key => simple(:k), :datetime => simple(:d)) {
56
+ Key.new(k.to_s, DateTime.iso8601(d))
57
+ }
58
+ rule(:key => simple(:k), :true => simple(:b)) { Key.new(k.to_s, true) }
59
+ rule(:key => simple(:k), :false => simple(:b)) { Key.new(k.to_s, false) }
60
+
61
+ # Make keys just be strings
62
+ rule(:key => simple(:k)) { k }
63
+
64
+ # Then objectify the key_groups
65
+ rule(:key_group => simple(:kg)) {
66
+ KeyGroup.new([kg.to_s])
67
+ }
68
+
69
+ # Captures array-like key-groups
70
+ rule(:key_group => subtree(:kg)) {
71
+ KeyGroup.new(kg.map &:to_s)
72
+ }
73
+ end
74
+ end
data/test/spec.toml ADDED
@@ -0,0 +1,43 @@
1
+ # Comment
2
+
3
+ # String
4
+ string = "string\n\t\"string"
5
+
6
+ # Integer
7
+ integer = 42
8
+
9
+ # Float
10
+ pi = 3.14159
11
+
12
+ # Booleans
13
+ true = true
14
+ false = false
15
+
16
+ # DateTime
17
+ datetime = 1979-05-27T07:32:00Z
18
+
19
+ # Keygroup
20
+ [a.b.c]
21
+ d = "test"
22
+
23
+ [e]
24
+ f = "test"
25
+
26
+ # Post line comment
27
+ [comments]
28
+ on = "a line" # with markup
29
+
30
+ # Multi-line arrays
31
+ [arrays]
32
+ # Simple array
33
+ simple = [1, 2, 3]
34
+
35
+ # Nested array
36
+ nested = [[[1], 2], 3]
37
+
38
+ multi = ["lines", "are",
39
+ "super", "cool", "lol",
40
+ "amirite"]
41
+
42
+ # Uneven spacing
43
+ uneven = [1, 2, 3, 4, 5 ]
@@ -0,0 +1,50 @@
1
+
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+
5
+ require 'toml'
6
+ require 'minitest/autorun'
7
+
8
+ class TestParser < MiniTest::Unit::TestCase
9
+ def setup
10
+ filepath = File.join(File.dirname(__FILE__), 'spec.toml')
11
+ @doc = TOML::Parser.new(File.read(filepath)).parsed
12
+ end
13
+
14
+ def test_string
15
+ assert_equal @doc["string"], "string\n\t\"string"
16
+ end
17
+
18
+ def test_integer
19
+ assert_equal @doc["integer"], 42
20
+ end
21
+
22
+ def test_float
23
+ assert_equal @doc["pi"], 3.14159
24
+ end
25
+
26
+ def test_datetime
27
+ assert_equal @doc["datetime"], DateTime.iso8601("1979-05-27T07:32:00Z")
28
+ end
29
+
30
+ def test_booleans
31
+ assert_equal @doc["true"], true
32
+ assert_equal @doc["false"], false
33
+ end
34
+
35
+ def test_simple_array
36
+ assert_equal @doc["arrays"]["simple"], [1, 2, 3]
37
+ end
38
+
39
+ def test_nested_array
40
+ assert_equal @doc["arrays"]["nested"], [[[1], 2], 3]
41
+ end
42
+
43
+ def test_simple_keygroup
44
+ assert_equal @doc["e"]["f"], "test"
45
+ end
46
+
47
+ def test_nested_keygroup
48
+ assert_equal @doc["a"]["b"]["c"]["d"], "test"
49
+ end
50
+ end
data/toml.gemspec CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'toml'
16
- s.version = '0.0.1'
17
- s.date = '2013-02-23'
16
+ s.version = '0.0.2'
17
+ s.date = '2013-02-24'
18
18
 
19
19
  ## Make sure your summary is short. The description may be as long
20
20
  ## as you like.
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
  ## List the primary authors. If there are a bunch of authors, it's probably
25
25
  ## better to set the email to an email list or something. If you don't have
26
26
  ## a custom homepage, consider using your GitHub URL or the like.
27
- s.authors = ["Jeremy McAnally"]
27
+ s.authors = ["Jeremy McAnally", "Dirk Gadsden"]
28
28
  s.email = 'jeremy@github.com'
29
29
  s.homepage = 'http://github.com/jm/toml'
30
30
 
@@ -36,17 +36,27 @@ Gem::Specification.new do |s|
36
36
  ## LICENSE files to the extra_rdoc_files list.
37
37
  s.rdoc_options = ["--charset=UTF-8"]
38
38
  s.extra_rdoc_files = %w[README.md LICENSE]
39
-
39
+
40
+ s.add_dependency 'parslet'
41
+
40
42
  ## Leave this section as-is. It will be automatically generated from the
41
43
  ## contents of your Git repository via the gemspec task. DO NOT REMOVE
42
44
  ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
43
45
  # = MANIFEST =
44
46
  s.files = %w[
47
+ Gemfile
48
+ Gemfile.lock
45
49
  LICENSE
46
50
  README.md
47
51
  Rakefile
48
52
  lib/toml.rb
53
+ lib/toml/key.rb
54
+ lib/toml/key_group.rb
49
55
  lib/toml/parser.rb
56
+ lib/toml/parslet.rb
57
+ lib/toml/transformer.rb
58
+ test/spec.toml
59
+ test/test_parser.rb
50
60
  toml.gemspec
51
61
  ]
52
62
  # = MANIFEST =
metadata CHANGED
@@ -1,16 +1,33 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jeremy McAnally
9
+ - Dirk Gadsden
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2013-02-23 00:00:00.000000000 Z
13
- dependencies: []
13
+ date: 2013-02-24 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: parslet
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
14
31
  description: Parse your TOML, seriously.
15
32
  email: jeremy@github.com
16
33
  executables: []
@@ -19,11 +36,19 @@ extra_rdoc_files:
19
36
  - README.md
20
37
  - LICENSE
21
38
  files:
39
+ - Gemfile
40
+ - Gemfile.lock
22
41
  - LICENSE
23
42
  - README.md
24
43
  - Rakefile
25
44
  - lib/toml.rb
45
+ - lib/toml/key.rb
46
+ - lib/toml/key_group.rb
26
47
  - lib/toml/parser.rb
48
+ - lib/toml/parslet.rb
49
+ - lib/toml/transformer.rb
50
+ - test/spec.toml
51
+ - test/test_parser.rb
27
52
  - toml.gemspec
28
53
  homepage: http://github.com/jm/toml
29
54
  licenses: []
@@ -50,4 +75,5 @@ rubygems_version: 1.8.23
50
75
  signing_key:
51
76
  specification_version: 2
52
77
  summary: Parse your TOML.
53
- test_files: []
78
+ test_files:
79
+ - test/test_parser.rb