edn 1.0.3 → 1.0.5
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 +4 -4
- data/README.md +94 -21
- data/Rakefile +5 -0
- data/edn.gemspec +4 -4
- data/lib/edn.rb +4 -20
- data/lib/edn/char_stream.rb +84 -0
- data/lib/edn/parser.rb +333 -201
- data/lib/edn/reader.rb +11 -24
- data/lib/edn/version.rb +1 -1
- data/spec/edn/char_stream_spec.rb +111 -0
- data/spec/edn/parser_spec.rb +31 -79
- data/spec/edn/reader_spec.rb +9 -9
- data/spec/edn_spec.rb +39 -5
- data/spec/spec_helper.rb +16 -4
- metadata +11 -26
- data/lib/edn/string_transformer.rb +0 -46
- data/lib/edn/transform.rb +0 -59
- data/lib/parslet/ignore.rb +0 -24
- data/spec/edn/transform_spec.rb +0 -176
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'edn'
|
3
|
-
require 'parslet/rig/rspec'
|
4
|
-
require 'parslet/convenience'
|
5
3
|
require 'rantly'
|
6
4
|
require 'date'
|
7
5
|
require 'time'
|
8
6
|
|
9
|
-
REPEAT = (ENV["REPEAT"] ||
|
7
|
+
REPEAT = (ENV["REPEAT"] || 150).to_i
|
10
8
|
|
11
9
|
RSpec.configure do |c|
|
12
10
|
c.fail_fast = true
|
@@ -19,6 +17,10 @@ RSpec.configure do |c|
|
|
19
17
|
c.run_all_when_everything_filtered = true
|
20
18
|
end
|
21
19
|
|
20
|
+
def io_for(s)
|
21
|
+
StringIO.new(s)
|
22
|
+
end
|
23
|
+
|
22
24
|
module RantlyHelpers
|
23
25
|
|
24
26
|
KEYWORD = lambda { |_|
|
@@ -47,7 +49,9 @@ module RantlyHelpers
|
|
47
49
|
|
48
50
|
STRING = lambda { |_| sized(range(1, 100)) { string.to_edn } }
|
49
51
|
|
50
|
-
|
52
|
+
RUBY_STRING = lambda { |_| sized(range(1, 100)) { string } }
|
53
|
+
|
54
|
+
FLOAT = lambda { |_| (float * range(-4000, 5000)).to_edn }
|
51
55
|
|
52
56
|
FLOAT_WITH_EXP = lambda { |_|
|
53
57
|
# limited range because of Infinity
|
@@ -59,6 +63,14 @@ module RantlyHelpers
|
|
59
63
|
join("")
|
60
64
|
}
|
61
65
|
|
66
|
+
RUBY_CHAR = lambda { |_|
|
67
|
+
"\\" +
|
68
|
+
sized(1) {
|
69
|
+
freq([1, [:choose, "\n", "\r", " ", "\t"]],
|
70
|
+
[5, [:string, :graph]])
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
62
74
|
CHARACTER = lambda { |_|
|
63
75
|
"\\" +
|
64
76
|
sized(1) {
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: edn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Clinton N. Dreisbach
|
7
|
+
- Clinton N. Dreisbach & Russ Olsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: parslet
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 1.4.0
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 1.4.0
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: pry
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,7 +68,7 @@ dependencies:
|
|
82
68
|
version: 10.0.3
|
83
69
|
description: "'edn implements a reader for Extensible Data Notation by Rich Hickey.'"
|
84
70
|
email:
|
85
|
-
-
|
71
|
+
- russ@russolsen.com
|
86
72
|
executables: []
|
87
73
|
extensions: []
|
88
74
|
extra_rdoc_files: []
|
@@ -96,27 +82,26 @@ files:
|
|
96
82
|
- Rakefile
|
97
83
|
- edn.gemspec
|
98
84
|
- lib/edn.rb
|
85
|
+
- lib/edn/char_stream.rb
|
99
86
|
- lib/edn/core_ext.rb
|
100
87
|
- lib/edn/metadata.rb
|
101
88
|
- lib/edn/parser.rb
|
102
89
|
- lib/edn/reader.rb
|
103
|
-
- lib/edn/string_transformer.rb
|
104
|
-
- lib/edn/transform.rb
|
105
90
|
- lib/edn/type/list.rb
|
106
91
|
- lib/edn/type/symbol.rb
|
107
92
|
- lib/edn/type/unknown.rb
|
108
93
|
- lib/edn/type/uuid.rb
|
109
94
|
- lib/edn/types.rb
|
110
95
|
- lib/edn/version.rb
|
111
|
-
-
|
96
|
+
- spec/edn/char_stream_spec.rb
|
112
97
|
- spec/edn/metadata_spec.rb
|
113
98
|
- spec/edn/parser_spec.rb
|
114
99
|
- spec/edn/reader_spec.rb
|
115
|
-
- spec/edn/transform_spec.rb
|
116
100
|
- spec/edn_spec.rb
|
117
101
|
- spec/spec_helper.rb
|
118
|
-
homepage:
|
119
|
-
licenses:
|
102
|
+
homepage: https://github.com/relevance/edn-ruby
|
103
|
+
licenses:
|
104
|
+
- MIT
|
120
105
|
metadata: {}
|
121
106
|
post_install_message:
|
122
107
|
rdoc_options: []
|
@@ -134,14 +119,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
119
|
version: '0'
|
135
120
|
requirements: []
|
136
121
|
rubyforge_project:
|
137
|
-
rubygems_version: 2.2.
|
122
|
+
rubygems_version: 2.2.1
|
138
123
|
signing_key:
|
139
124
|
specification_version: 4
|
140
125
|
summary: "'edn implements a reader for Extensible Data Notation by Rich Hickey.'"
|
141
126
|
test_files:
|
127
|
+
- spec/edn/char_stream_spec.rb
|
142
128
|
- spec/edn/metadata_spec.rb
|
143
129
|
- spec/edn/parser_spec.rb
|
144
130
|
- spec/edn/reader_spec.rb
|
145
|
-
- spec/edn/transform_spec.rb
|
146
131
|
- spec/edn_spec.rb
|
147
132
|
- spec/spec_helper.rb
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module EDN
|
2
|
-
module StringTransformer
|
3
|
-
# Unescape characters in strings.
|
4
|
-
# Borrowed from json-pure gem.
|
5
|
-
UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
|
6
|
-
UNESCAPE_MAP.update({ ?" => '"',
|
7
|
-
?\\ => '\\',
|
8
|
-
?/ => '/',
|
9
|
-
#' Clear messed up syntax highlighting with Emacs.
|
10
|
-
?b => "\b",
|
11
|
-
?f => "\f",
|
12
|
-
?n => "\n",
|
13
|
-
?r => "\r",
|
14
|
-
?t => "\t",
|
15
|
-
?u => nil,
|
16
|
-
})
|
17
|
-
|
18
|
-
EMPTY_8BIT_STRING = ''
|
19
|
-
if ::String.method_defined?(:encode)
|
20
|
-
EMPTY_8BIT_STRING.force_encoding Encoding::ASCII_8BIT
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.parse_string(string)
|
24
|
-
string = string.to_s
|
25
|
-
return '' if string.empty?
|
26
|
-
string = string.gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
|
27
|
-
#" Clear messed up syntax highlighting with Emacs.
|
28
|
-
if u = UNESCAPE_MAP[$&[1]]
|
29
|
-
u
|
30
|
-
else # \uXXXX
|
31
|
-
bytes = EMPTY_8BIT_STRING.dup
|
32
|
-
i = 0
|
33
|
-
while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
|
34
|
-
bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
|
35
|
-
i += 1
|
36
|
-
end
|
37
|
-
JSON.iconv('utf-8', 'utf-16be', bytes)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
if string.respond_to?(:force_encoding)
|
41
|
-
string.force_encoding(::Encoding::UTF_8)
|
42
|
-
end
|
43
|
-
string
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
data/lib/edn/transform.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'edn/string_transformer'
|
2
|
-
require 'edn/types'
|
3
|
-
require 'edn/metadata'
|
4
|
-
require 'bigdecimal'
|
5
|
-
|
6
|
-
module EDN
|
7
|
-
class Transform < Parslet::Transform
|
8
|
-
rule(:true => simple(:x)) { true }
|
9
|
-
rule(:false => simple(:x)) { false }
|
10
|
-
rule(:nil => simple(:x)) { nil }
|
11
|
-
|
12
|
-
rule(:integer => simple(:num), :precision => simple(:n)) {
|
13
|
-
Integer(num)
|
14
|
-
}
|
15
|
-
rule(:float => simple(:num), :precision => simple(:n)) {
|
16
|
-
if n
|
17
|
-
BigDecimal(num)
|
18
|
-
else
|
19
|
-
Float(num)
|
20
|
-
end
|
21
|
-
}
|
22
|
-
|
23
|
-
rule(:string => []) { "" }
|
24
|
-
rule(:string => simple(:x)) { EDN::StringTransformer.parse_string(x) }
|
25
|
-
rule(:keyword => simple(:x)) { x.to_sym }
|
26
|
-
rule(:symbol => simple(:x)) { EDN::Type::Symbol.new(x) }
|
27
|
-
rule(:character => simple(:x)) {
|
28
|
-
case x
|
29
|
-
when "newline" then "\n"
|
30
|
-
when "return" then "\r"
|
31
|
-
when "tab" then "\t"
|
32
|
-
when "space" then " "
|
33
|
-
else x.to_s
|
34
|
-
end
|
35
|
-
}
|
36
|
-
|
37
|
-
rule(:vector => subtree(:array)) { array }
|
38
|
-
rule(:list => subtree(:array)) { EDN::Type::List.new(*array) }
|
39
|
-
rule(:set => subtree(:array)) { Set.new(array) }
|
40
|
-
rule(:map => subtree(:array)) { Hash[array.map { |hash| [hash[:key], hash[:value]] }] }
|
41
|
-
|
42
|
-
rule(:tag => simple(:tag), :element => subtree(:element)) {
|
43
|
-
EDN.tagged_element(tag.to_s, element)
|
44
|
-
}
|
45
|
-
|
46
|
-
rule(:metadata => subtree(:raw_metadata), :element => subtree(:element)) {
|
47
|
-
metadata = raw_metadata.reverse.reduce({}) do |acc, m|
|
48
|
-
case m
|
49
|
-
when Symbol then acc.merge(m => true)
|
50
|
-
when EDN::Type::Symbol then acc.merge(:tag => m)
|
51
|
-
else acc.merge(m)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
element.extend EDN::Metadata
|
55
|
-
element.metadata = metadata
|
56
|
-
element
|
57
|
-
}
|
58
|
-
end
|
59
|
-
end
|
data/lib/parslet/ignore.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
class IgnoreParslet < Parslet::Atoms::Base
|
2
|
-
def initialize(parslet)
|
3
|
-
@parslet = parslet
|
4
|
-
end
|
5
|
-
def to_s_inner(prec)
|
6
|
-
@parslet.to_s(prec)
|
7
|
-
end
|
8
|
-
def try(source, context)
|
9
|
-
success, value = result = @parslet.try(source, context)
|
10
|
-
|
11
|
-
return succ(nil) if success
|
12
|
-
return result
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module IgnoreDSL
|
17
|
-
def ignore
|
18
|
-
IgnoreParslet.new(self)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Parslet::Atoms::Base
|
23
|
-
include IgnoreDSL
|
24
|
-
end
|
data/spec/edn/transform_spec.rb
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe EDN::Transform do
|
4
|
-
context "integer" do
|
5
|
-
it "should emit an integer" do
|
6
|
-
subject.apply(:integer => "1", :precision => nil).should == 1
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
context "float" do
|
11
|
-
it "should emit an float" do
|
12
|
-
subject.apply(:float => "1.0", :precision => nil).should == 1.0
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should emit a BigDecimal if suffixed with M" do
|
16
|
-
subject.apply(:float => "1.0", :precision => "M").should == BigDecimal("1.0")
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
context "string" do
|
21
|
-
it "should emit a string with control characters substituted" do
|
22
|
-
subject.apply(:string => 'hello\nworld').should == "hello\nworld"
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should not evaluate interpolated Ruby code" do
|
26
|
-
subject.apply(:string => 'hello\n#{world}').should == "hello\n\#{world}"
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should emit empty strings as strings" do
|
30
|
-
subject.apply(:string => []).should == ""
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
context "keyword" do
|
35
|
-
it "should emit a Ruby symbol" do
|
36
|
-
subject.apply(:keyword => "test").should == :test
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context "symbol" do
|
41
|
-
it "should emit an EDN symbol" do
|
42
|
-
subject.apply(:symbol => "test").should == ~'test'
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context "boolean" do
|
47
|
-
it "should emit true or false" do
|
48
|
-
subject.apply(:true => "true").should == true
|
49
|
-
subject.apply(:false => "false").should == false
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
context "nil" do
|
54
|
-
it "should emit nil" do
|
55
|
-
subject.apply(:nil => "nil").should == nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context "character" do
|
60
|
-
it "should emit a string" do
|
61
|
-
subject.apply(:character => "&").should == "&"
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should handle newline, space, and tab special cases" do
|
65
|
-
subject.apply(:character => "newline").should == "\n"
|
66
|
-
subject.apply(:character => "space").should == " "
|
67
|
-
subject.apply(:character => "tab").should == "\t"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context "vector" do
|
72
|
-
it "should emit an array" do
|
73
|
-
subject.apply(:vector => []).should == []
|
74
|
-
subject.apply(:vector => [{:integer => "1", :precision => nil}, {:string => "abc"}]).should == [1, "abc"]
|
75
|
-
subject.apply(:vector => [{:vector => [{:integer => "1", :precision => nil}, {:string => "abc"}]}, {:float => "3.14", :precision => nil}]).should == [[1, "abc"], 3.14]
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context "list" do
|
80
|
-
it "should emit a list" do
|
81
|
-
subject.apply(:list => []).should == EDN.list
|
82
|
-
subject.apply(:list => [{:integer => "1", :precision => nil}, {:string => "abc"}]).should == ~[1, "abc"]
|
83
|
-
subject.apply(:list => [{:list => [{:integer => "1", :precision => nil}, {:string => "abc"}]}, {:float => "3.14", :precision => nil}]).should == \
|
84
|
-
~[~[1, "abc"], 3.14]
|
85
|
-
end
|
86
|
-
|
87
|
-
it "should be type-compatible with arrays" do
|
88
|
-
subject.apply(:list => [{:integer => "1", :precision => nil}, {:string => "abc"}]).should == [1, "abc"]
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
context "set" do
|
93
|
-
it "should emit a set" do
|
94
|
-
subject.apply(:set => []).should == Set.new
|
95
|
-
subject.apply(:set => [1, "abc", 2]).should == Set.new([1, "abc", 2])
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
context "map" do
|
100
|
-
it "should emit a hash" do
|
101
|
-
map_tree = {:map=>
|
102
|
-
[ {:key=>{:keyword=>{:symbol=>"a"}}, :value=>{:integer=>"1", :precision => nil}},
|
103
|
-
{:key=>{:keyword=>{:symbol=>"b"}}, :value=>{:integer=>"2", :precision => nil}}
|
104
|
-
]
|
105
|
-
}
|
106
|
-
|
107
|
-
subject.apply(map_tree).should == {:a => 1, :b => 2}
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should work with nested maps" do
|
111
|
-
map_tree = {:map=>
|
112
|
-
[{:key=>{:keyword=>{:symbol=>"a"}}, :value=>{:integer=>"1", :precision => nil}},
|
113
|
-
{:key=>{:keyword=>{:symbol=>"b"}}, :value=>{:integer=>"2", :precision => nil}},
|
114
|
-
{:key=>
|
115
|
-
{:map=>
|
116
|
-
[{:key=>{:keyword=>{:symbol=>"c"}}, :value=>{:integer=>"3", :precision => nil}}]},
|
117
|
-
:value=>{:integer=>"4", :precision => nil}}]}
|
118
|
-
subject.apply(map_tree).should == {:a => 1, :b => 2, {:c => 3} => 4}
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
context "tagged element" do
|
123
|
-
it "should emit a EDN::Type::Unknown if the tag is not registered" do
|
124
|
-
subject.apply({:tag => {:symbol => 'uri'}, :element => {:string => 'http://google.com'}}).should == EDN::Type::Unknown.new("uri", "http://google.com")
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should emit the transformed element if the tag is registered" do
|
128
|
-
EDN.register("uri", lambda { |uri| URI(uri) })
|
129
|
-
subject.apply({:tag => {:symbol => 'uri'}, :element => {:string => 'http://google.com'}}).should == URI("http://google.com")
|
130
|
-
EDN.unregister("uri") # cleanup
|
131
|
-
end
|
132
|
-
|
133
|
-
it "should work with nested elements" do
|
134
|
-
tree = {
|
135
|
-
:tag=>{:symbol=>"cnd/awesome"},
|
136
|
-
:element=>
|
137
|
-
{:vector=>
|
138
|
-
[{:keyword=>{:symbol=>"a"}},
|
139
|
-
{:list=>
|
140
|
-
[{:integer=>"1", :precision=>nil},
|
141
|
-
{:list=>
|
142
|
-
[{:integer=>"2", :precision=>nil},
|
143
|
-
{:integer=>"3", :precision=>nil}]}]},
|
144
|
-
{:keyword=>{:symbol=>"b"}},
|
145
|
-
{:keyword=>{:symbol=>"c"}},
|
146
|
-
{:set=>
|
147
|
-
[{:integer=>"1", :precision=>nil},
|
148
|
-
{:integer=>"2", :precision=>nil},
|
149
|
-
{:integer=>"3", :precision=>nil}]},
|
150
|
-
{:vector=>
|
151
|
-
[{:vector=>
|
152
|
-
[{:vector=>[{:integer=>"42", :precision=>nil}]},
|
153
|
-
{:integer=>"42", :precision=>nil}]}]}]}}
|
154
|
-
expected = EDN::Type::Unknown.new('cnd/awesome',
|
155
|
-
[:a, [1, [2, 3]], :b, :c,
|
156
|
-
Set.new([1, 2, 3]), [[[42], 42]]])
|
157
|
-
subject.apply(tree).should == expected
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
context "element with metadata" do
|
162
|
-
it "should tag the element with metadata" do
|
163
|
-
tree = {
|
164
|
-
:metadata =>
|
165
|
-
[:map =>
|
166
|
-
[
|
167
|
-
{:key=>{:keyword=>{:symbol=>"a"}}, :value=>{:integer=>"1", :precision => nil}},
|
168
|
-
{:key=>{:keyword=>{:symbol=>"b"}}, :value=>{:integer=>"2", :precision => nil}}]],
|
169
|
-
:element => {:vector => [{:integer => "1", :precision => nil}, {:string => "abc"}]}}
|
170
|
-
|
171
|
-
element = subject.apply(tree)
|
172
|
-
element.should == [1, "abc"]
|
173
|
-
element.metadata.should == {:a => 1, :b => 2}
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|