edn2023 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +29 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +268 -0
- data/Rakefile +12 -0
- data/edn2023.gemspec +22 -0
- data/lib/edn/char_stream.rb +84 -0
- data/lib/edn/core_ext.rb +112 -0
- data/lib/edn/metadata.rb +27 -0
- data/lib/edn/parser.rb +92 -0
- data/lib/edn/reader.rb +23 -0
- data/lib/edn/ruby_edn_parser.rb +266 -0
- data/lib/edn/type/list.rb +13 -0
- data/lib/edn/type/symbol.rb +39 -0
- data/lib/edn/type/unknown.rb +9 -0
- data/lib/edn/type/uuid.rb +9 -0
- data/lib/edn/types.rb +3 -0
- data/lib/edn/version.rb +3 -0
- data/lib/edn.rb +80 -0
- data/spec/edn/char_stream_spec.rb +111 -0
- data/spec/edn/metadata_spec.rb +38 -0
- data/spec/edn/parser_spec.rb +162 -0
- data/spec/edn/reader_spec.rb +23 -0
- data/spec/edn_spec.rb +114 -0
- data/spec/exemplars/big_decimal.edn +1 -0
- data/spec/exemplars/big_decimal.rb +1 -0
- data/spec/exemplars/big_int.edn +1 -0
- data/spec/exemplars/big_int.rb +1 -0
- data/spec/exemplars/char.edn +1 -0
- data/spec/exemplars/char.rb +1 -0
- data/spec/exemplars/empty_string.edn +1 -0
- data/spec/exemplars/empty_string.rb +1 -0
- data/spec/exemplars/false.edn +1 -0
- data/spec/exemplars/false.rb +1 -0
- data/spec/exemplars/float.edn +1 -0
- data/spec/exemplars/float.rb +1 -0
- data/spec/exemplars/float_neg_exp.edn +1 -0
- data/spec/exemplars/float_neg_exp.rb +1 -0
- data/spec/exemplars/float_point_dec_neg_exp.edn +1 -0
- data/spec/exemplars/float_point_dec_neg_exp.rb +1 -0
- data/spec/exemplars/float_point_plus_exp.edn +1 -0
- data/spec/exemplars/float_point_plus_exp.rb +1 -0
- data/spec/exemplars/float_pointneg_exp.edn +1 -0
- data/spec/exemplars/float_pointneg_exp.rb +1 -0
- data/spec/exemplars/float_pos_exp.edn +1 -0
- data/spec/exemplars/float_pos_exp.rb +1 -0
- data/spec/exemplars/float_sign_exp.edn +1 -0
- data/spec/exemplars/float_sign_exp.rb +1 -0
- data/spec/exemplars/float_with_exp.edn +1 -0
- data/spec/exemplars/float_with_exp.rb +1 -0
- data/spec/exemplars/float_with_exp_no_dec.edn +1 -0
- data/spec/exemplars/float_with_exp_no_dec.rb +1 -0
- data/spec/exemplars/gt_symbol.edn +1 -0
- data/spec/exemplars/gt_symbol.rb +1 -0
- data/spec/exemplars/integer.edn +1 -0
- data/spec/exemplars/integer.rb +1 -0
- data/spec/exemplars/keyword.edn +1 -0
- data/spec/exemplars/keyword.rb +1 -0
- data/spec/exemplars/keyword_with_namespace.edn +1 -0
- data/spec/exemplars/keyword_with_namespace.rb +1 -0
- data/spec/exemplars/list_empty.edn +1 -0
- data/spec/exemplars/list_empty.rb +1 -0
- data/spec/exemplars/list_mixed.edn +1 -0
- data/spec/exemplars/list_mixed.rb +1 -0
- data/spec/exemplars/list_nested.edn +1 -0
- data/spec/exemplars/list_nested.rb +1 -0
- data/spec/exemplars/list_one_element.edn +1 -0
- data/spec/exemplars/list_one_element.rb +1 -0
- data/spec/exemplars/long_string.edn +1 -0
- data/spec/exemplars/long_string.rb +1 -0
- data/spec/exemplars/map_empty.edn +1 -0
- data/spec/exemplars/map_empty.rb +1 -0
- data/spec/exemplars/map_nested.edn +1 -0
- data/spec/exemplars/map_nested.rb +1 -0
- data/spec/exemplars/map_one_element.edn +1 -0
- data/spec/exemplars/map_one_element.rb +1 -0
- data/spec/exemplars/map_two_entry.edn +1 -0
- data/spec/exemplars/map_two_entry.rb +1 -0
- data/spec/exemplars/mmv +4 -0
- data/spec/exemplars/nil.edn +1 -0
- data/spec/exemplars/nil.rb +1 -0
- data/spec/exemplars/set_empty.edn +1 -0
- data/spec/exemplars/set_empty.rb +1 -0
- data/spec/exemplars/set_nested.edn +1 -0
- data/spec/exemplars/set_nested.rb +1 -0
- data/spec/exemplars/set_one_element.edn +1 -0
- data/spec/exemplars/set_one_element.rb +1 -0
- data/spec/exemplars/set_two_elements.edn +1 -0
- data/spec/exemplars/set_two_elements.rb +1 -0
- data/spec/exemplars/simple_skip.edn +1 -0
- data/spec/exemplars/simple_skip.rb +1 -0
- data/spec/exemplars/skip_more_space.edn +1 -0
- data/spec/exemplars/skip_more_space.rb +1 -0
- data/spec/exemplars/skip_more_vector_elements.edn +1 -0
- data/spec/exemplars/skip_more_vector_elements.rb +1 -0
- data/spec/exemplars/skip_some_vector_elements.edn +1 -0
- data/spec/exemplars/skip_some_vector_elements.rb +1 -0
- data/spec/exemplars/skip_two_vector_elements.edn +1 -0
- data/spec/exemplars/skip_two_vector_elements.rb +1 -0
- data/spec/exemplars/skip_vector_element.edn +1 -0
- data/spec/exemplars/skip_vector_element.rb +1 -0
- data/spec/exemplars/skip_with_spaces.edn +1 -0
- data/spec/exemplars/skip_with_spaces.rb +1 -0
- data/spec/exemplars/skip_yet_more_space.edn +1 -0
- data/spec/exemplars/skip_yet_more_space.rb +1 -0
- data/spec/exemplars/special_symbol.edn +1 -0
- data/spec/exemplars/special_symbol.rb +1 -0
- data/spec/exemplars/string_with_newline.edn +1 -0
- data/spec/exemplars/string_with_newline.rb +1 -0
- data/spec/exemplars/symbol.edn +1 -0
- data/spec/exemplars/symbol.rb +1 -0
- data/spec/exemplars/symbol_begins_with_false.edn +1 -0
- data/spec/exemplars/symbol_begins_with_false.rb +1 -0
- data/spec/exemplars/symbol_begins_with_nil.edn +1 -0
- data/spec/exemplars/symbol_begins_with_nil.rb +1 -0
- data/spec/exemplars/symbol_with_dash.edn +1 -0
- data/spec/exemplars/symbol_with_dash.rb +1 -0
- data/spec/exemplars/symbol_with_namespace.edn +1 -0
- data/spec/exemplars/symbol_with_namespace.rb +1 -0
- data/spec/exemplars/tagged_instant.edn +1 -0
- data/spec/exemplars/tagged_instant.rb +1 -0
- data/spec/exemplars/tagged_uuid.edn +1 -0
- data/spec/exemplars/tagged_uuid.rb +1 -0
- data/spec/exemplars/true.edn +1 -0
- data/spec/exemplars/true.rb +1 -0
- data/spec/exemplars/utf8.edn +1 -0
- data/spec/exemplars/utf8.rb +1 -0
- data/spec/exemplars/vector_empty.edn +1 -0
- data/spec/exemplars/vector_empty.rb +1 -0
- data/spec/exemplars/vector_mixed.edn +1 -0
- data/spec/exemplars/vector_mixed.rb +1 -0
- data/spec/exemplars/vector_nested.edn +1 -0
- data/spec/exemplars/vector_nested.rb +1 -0
- data/spec/exemplars/vector_one_element.edn +1 -0
- data/spec/exemplars/vector_one_element.rb +1 -0
- data/spec/exemplars/whole_number_with_exp.edn +1 -0
- data/spec/exemplars/whole_number_with_exp.rb +1 -0
- data/spec/spec_helper.rb +164 -0
- metadata +357 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b6536c5d243ceaf4962408fcdf528d7bf983b13223284562de5377ab692a7f2e
|
4
|
+
data.tar.gz: 8b186c8112be6fbf2194562b20a538780cfc118bb819ec0098a4a89a77b856fa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7ae3d3d1b5ee8449e977644c11fc0f6aa546d13556bbc687a6526658e162f7190608ff68f42763f79fbe8d34a85353d741d716ded46f1017fe2fb0e881b8c9f0
|
7
|
+
data.tar.gz: aae587f32dca3595f9a3a4526175ed6af9488e9c3a1be5c706bab3ec6d3ccb8568cf70638e63ffc3e6fc426c4b21c2379b4672f688e9b0abcee795b150c20b9a
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# 1.1.4 (March 9, 2023)
|
2
|
+
|
3
|
+
* Forked to support Ruby 3.2. <https://github.com/edn2023/edn2023> New RubyGem `edn2023`. (@edn2023)
|
4
|
+
|
5
|
+
|
6
|
+
# 1.1.2 (January 13, 2020)
|
7
|
+
|
8
|
+
* BigDecimal.new() -> BigDecimal() for Ruby 2.7 (BigDecimal 2). (@caleb)
|
9
|
+
|
10
|
+
|
11
|
+
# 1.0.2
|
12
|
+
* Handle numbers with M precision
|
13
|
+
|
14
|
+
# 1.0.1
|
15
|
+
* EDN.register defaults to the identity function when no handler is given
|
16
|
+
|
17
|
+
# 0.9.4 (18 Sep 2012)
|
18
|
+
|
19
|
+
* Require `set`
|
20
|
+
|
21
|
+
# 0.9.3 (17 Sep 2012)
|
22
|
+
|
23
|
+
* Updated to latest EDN spec
|
24
|
+
** Added new symbol characters
|
25
|
+
** Added ability to have a + before a number
|
26
|
+
|
27
|
+
# 0.9.2 (13 Sep 2012)
|
28
|
+
|
29
|
+
* EDN spec fully implemented
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Relevance Inc & Clinton N. Dreisbach
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
# edn2023
|
2
|
+
|
3
|
+
© 2012 Relevance Inc
|
4
|
+
|
5
|
+
**edn2023** is a Ruby library to read and write EDN (extensible data notation), a subset of Clojure used for transferring data between applications, much like JSON, YAML, or XML.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
If the `edn` gem is installed it should be uninstalled:
|
10
|
+
|
11
|
+
$ gem uninstall edn
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'edn2023'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install edn2023
|
24
|
+
|
25
|
+
|
26
|
+
Note that you might also want to look at [edn_turbo](https://github.com/edporras/edn_turbo)
|
27
|
+
which provides a much faster EDN parser (It's written in C) with an interface that is largely compatible
|
28
|
+
with ths gem.
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
To read a string of EDN:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
require 'edn'
|
36
|
+
EDN.read('[1 2 {:foo "bar"}]')
|
37
|
+
```
|
38
|
+
|
39
|
+
Alternatively you can pass in an IO instance, for
|
40
|
+
example an open file:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
File.open("data.edn") do |f|
|
44
|
+
data = EDN.read(f)
|
45
|
+
# Do something with data
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
By default EDN.read will throw an execption
|
50
|
+
if you try to read past the end of the data:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
EDN.read("") # Boom!
|
54
|
+
```
|
55
|
+
|
56
|
+
Alternatively, the `EDN.read` method takes an optional
|
57
|
+
parameter, which is the value to return
|
58
|
+
when it hits the end of data:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
EDN.read("", :nomore)
|
62
|
+
|
63
|
+
#=> :nomore
|
64
|
+
```
|
65
|
+
|
66
|
+
There is no problem using `nil` as an eof value.
|
67
|
+
|
68
|
+
### EDN::Reader
|
69
|
+
|
70
|
+
You can also do things in a more object oriented way by
|
71
|
+
creating instances of `EDN::Reader`:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
r = EDN::Reader.new('[1 2 3] {:a 1 :b 2}')
|
75
|
+
|
76
|
+
r.read #=> [1, 2, 3]
|
77
|
+
r.read #=> {:a => 1, :b => 2}
|
78
|
+
r.read #=> RuntimeError: Unexpected end of file
|
79
|
+
```
|
80
|
+
|
81
|
+
`EDN:Reader` will also take an IO instance:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
r = EDN::Reader.new(open("data.edn"))
|
85
|
+
|
86
|
+
r.read # Read the first form from the file.
|
87
|
+
r.read # Read the second form from the file.
|
88
|
+
r.read # Read the third from from the file.
|
89
|
+
```
|
90
|
+
|
91
|
+
You can also iterate through the forms with `each`:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
r = EDN::Reader.new('[1 2 3] {:a 1 :b 2}')
|
95
|
+
|
96
|
+
r.each do |form|
|
97
|
+
p form
|
98
|
+
end
|
99
|
+
|
100
|
+
#=> [1, 2, 3]
|
101
|
+
#=> {:a => 1, :b => 2}
|
102
|
+
```
|
103
|
+
|
104
|
+
Note that in contrast to earlier versions of this gem,
|
105
|
+
EDN::Reader is no longer `Enumerable`.
|
106
|
+
|
107
|
+
Like `EDN.read`, `Reader.read` also takes an optional
|
108
|
+
parameter, which is returned when there is no more data:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
r = EDN::Reader.new('1 2 3')
|
112
|
+
r.read(:eof) # returns 1
|
113
|
+
r.read(:eof) # returns 2
|
114
|
+
r.read(:eof) # returns 3
|
115
|
+
r.read(:eof) # returns :eof
|
116
|
+
```
|
117
|
+
|
118
|
+
### Converting Ruby data to EDN
|
119
|
+
|
120
|
+
To convert a data structure to an EDN string:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
data.to_edn
|
124
|
+
```
|
125
|
+
|
126
|
+
By default, this will work for strings, symbols, numbers, arrays, hashes, sets, nil, Time, and boolean values.
|
127
|
+
|
128
|
+
### Value Translations
|
129
|
+
|
130
|
+
Note that EDN uses its own terminology for the types of objects it represents
|
131
|
+
and in some cases those types not map cleanly to Ruby.
|
132
|
+
|
133
|
+
In EDN, you have _keywords_, which look like Ruby symbols and have the same meaning and
|
134
|
+
purpose. These are converted to Ruby symbols.
|
135
|
+
|
136
|
+
You also have EDN _symbols_, which generally reflect variable names, but have
|
137
|
+
several purposes. We parse these and return `EDN::Type::Symbol` values for them,
|
138
|
+
as they don't map to anything built into Ruby. To create an EDN symbol in Ruby,
|
139
|
+
call `EDN::Type::Symbol.new` or `EDN.symbol` with a string argument, or use the
|
140
|
+
convenience unary operator `~` like so: `~"elf/rings"`.
|
141
|
+
|
142
|
+
EDN also has _vectors_, which map to Ruby arrays, and _lists_, which are linked lists
|
143
|
+
in Clojure. We map EDN lists to `EDN::Type::List` values, which are type-compatible with
|
144
|
+
arrays. To create an EDN list in Ruby, call `EDN::Type::List.new` or `EDN.list`
|
145
|
+
with all arguments to go in the list. If you have an array, you will use the splat
|
146
|
+
operator, like so: `EDN.list(*[1, 2, 3])`. You can also use the `~` unary
|
147
|
+
operator like so: `~[1, 2, 3]`.
|
148
|
+
|
149
|
+
EDN also has character types, but Ruby does not. These are converted into one-character strings.
|
150
|
+
|
151
|
+
### Tagged Values
|
152
|
+
|
153
|
+
The interesting part of EDN is the _extensible_ part.
|
154
|
+
Data can be be _tagged_ to coerce interpretation of
|
155
|
+
it to a particular data type. An example of a tagged data element:
|
156
|
+
|
157
|
+
```
|
158
|
+
#wolf/pack {:alpha "Greybeard" :betas ["Frostpaw" "Blackwind" "Bloodjaw"]}
|
159
|
+
```
|
160
|
+
|
161
|
+
The tag (`#wolf/pack`) will tell any consumers of this data
|
162
|
+
to use a data type registered to handle `wolf/pack` to represent this data.
|
163
|
+
|
164
|
+
The rules for tags from the [EDN README][README] should be followed. In short, custom tags should have a prefix (the part before the `/`) designating the user that created them or context they are used in. Non-prefixed tags are reserved for built-in tags.
|
165
|
+
|
166
|
+
There are two tags built in by default: `#uuid`, used for UUIDs, and `#inst`, used for an instant in time. In `edn-ruby`, `#inst` is converted to a Time, and Time values are tagged as `#inst`. There is not a UUID data type built into Ruby, so `#uuid` is converted to an instance of `EDN::Type::UUID`.
|
167
|
+
|
168
|
+
Tags that are not registered generate a struct of the type `EDN::Type::Unknown` with the methods `tag` and `value`.
|
169
|
+
|
170
|
+
### Registering a New Tag For Reading
|
171
|
+
|
172
|
+
To register a tag for reading, call the method `EDN.register` with a tag and one of the following:
|
173
|
+
|
174
|
+
- A block that accepts data and returns a value.
|
175
|
+
- A lambda that accepts data and returns a value.
|
176
|
+
- A class that has an `initialize` method that accepts data.
|
177
|
+
|
178
|
+
Examples:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
EDN.register("clinton/uri") do |uri|
|
182
|
+
URI(uri)
|
183
|
+
end
|
184
|
+
|
185
|
+
EDN.register("clinton/date", lambda { |date_array| Date.new(*date_array) })
|
186
|
+
|
187
|
+
class Dog
|
188
|
+
def initialize(name)
|
189
|
+
@name = name
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
EDN.register("clinton/dog", Dog)
|
194
|
+
```
|
195
|
+
|
196
|
+
### Writing Tags
|
197
|
+
|
198
|
+
Writing tags should be done as part of the class's `.to_edn` method, like so:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
class Dog
|
202
|
+
def to_edn
|
203
|
+
["#clinton/dog", @name.to_edn].join(" ")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
`EDN` provides a helper method, `EDN.tagout`:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
class Dog
|
212
|
+
def to_edn
|
213
|
+
EDN.tagout("clinton/dog", @name)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
This method calls `.to_edn` on the second argument and joins the arguments appropriately.
|
219
|
+
|
220
|
+
Other examples are:
|
221
|
+
```
|
222
|
+
EDN.tagout("wolf/pack", {:alpha=>"Greybeard", :betas=>["Frostpaw", "Blackwind", "Bloodjaw"]})
|
223
|
+
=> "#wolf/pack {:alpha \"Greybeard\", :betas [\"Frostpaw\" \"Blackwind\" \"Bloodjaw\"]}"
|
224
|
+
|
225
|
+
class Range
|
226
|
+
def to_edn
|
227
|
+
EDN.tagout("ruby/range", [self.begin, self.end, self.exclude_end?])
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
(0..9).to_edn
|
232
|
+
=> "#ruby/range [0 9 false]"
|
233
|
+
```
|
234
|
+
|
235
|
+
|
236
|
+
## Metadata
|
237
|
+
|
238
|
+
Certain elements of EDN can have *metadata*. Metadata is a map of values about the element, which must follow specific rules.
|
239
|
+
|
240
|
+
* Only symbols, lists, vectors, maps, and sets can have metadata. Tagged elements *cannot* have metadata.
|
241
|
+
* Metadata keys must be symbols, keywords, or strings.
|
242
|
+
|
243
|
+
Metadata can be expressed in one of the following three ways:
|
244
|
+
|
245
|
+
* Via a map. The element is prefixed with a map which has a caret (`^`) prefixed to it, like so: `^{:doc "This is my vector" :rel :temps} [98.6 99.7]`.
|
246
|
+
* Via a keyword. The element is prefixed with a keyword, also prefixed by a caret: `^:awesome #{1 2 \c}`. This results in the key `:awesome` being set to `true`, as if the metadata was: `^{:awesome true} #{1 2 \c}`.
|
247
|
+
* Via a symbol. The element is prefixed with a symbol, also prefixed by a caret: `^Boolean "true"`. This results in the key `:tag` being set to the symbol, as if the metadata was: `^{:tag Boolean} "true"`. This is used in Clojure to indicate the Java type of the element. In other EDN implementations, it may be ignored or used differently.
|
248
|
+
|
249
|
+
More than one piece of metadata can be applied to an element. Metadata is applied to the next element appearing after it, so in the case of `^:foo ^{:bar false} [1 2]`, the metadata would be, in total, `^{:foo true, :bar false}`. Note that `^:foo` is applied to the element `[1 2]` with the metadata `^{:bar false}` applied to it. Because of this, key collisions are resolved *right-to-left*.
|
250
|
+
|
251
|
+
## Contributors
|
252
|
+
|
253
|
+
* Clinton N. Dreisbach (@crnixon)
|
254
|
+
* Michael Ficarra (@michaelficarra)
|
255
|
+
* Andrew Forward (@aforward)
|
256
|
+
* Gabriel Horner (@cldwalker)
|
257
|
+
* Russ Olsen (@russolsen)
|
258
|
+
|
259
|
+
## Contributing
|
260
|
+
|
261
|
+
1. Fork it
|
262
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
263
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
264
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
265
|
+
5. Create new Pull Request
|
266
|
+
|
267
|
+
[edn]: https://github.com/edn-format/edn
|
268
|
+
[README]: https://github.com/edn-format/edn/blob/master/README.md
|
data/Rakefile
ADDED
data/edn2023.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/edn/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Clinton N. Dreisbach & Russ Olsen"]
|
6
|
+
gem.description = %q{edn implements a reader for Extensible Data Notation by Rich Hickey.}
|
7
|
+
gem.summary = gem.description
|
8
|
+
gem.homepage = "https://github.com/edn2023/edn2023"
|
9
|
+
gem.license = "MIT"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "edn2023"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = EDN::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency 'pry'
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_development_dependency 'rantly'
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module EDN
|
5
|
+
class CharStream
|
6
|
+
def initialize(io=$stdin)
|
7
|
+
@io = io
|
8
|
+
@current = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def current
|
12
|
+
return @current if @current
|
13
|
+
advance
|
14
|
+
end
|
15
|
+
|
16
|
+
def advance
|
17
|
+
return @current if @current == :eof
|
18
|
+
@current = @io.getc || :eof
|
19
|
+
end
|
20
|
+
|
21
|
+
def digit?(c=current)
|
22
|
+
/[0-9]/ =~ c
|
23
|
+
end
|
24
|
+
|
25
|
+
def alpha?(c=current)
|
26
|
+
/[a-zA-Z]/ =~ c
|
27
|
+
end
|
28
|
+
|
29
|
+
def eof?(c=current)
|
30
|
+
c == :eof
|
31
|
+
end
|
32
|
+
|
33
|
+
def ws?(c=current)
|
34
|
+
/[ \t\r\n,]/ =~ c
|
35
|
+
end
|
36
|
+
|
37
|
+
def newline?(c=current)
|
38
|
+
/[\n\r]/ =~ c
|
39
|
+
end
|
40
|
+
|
41
|
+
def repeat(pattern, &block)
|
42
|
+
result = nil
|
43
|
+
while current =~ pattern
|
44
|
+
result ||= ''
|
45
|
+
result = block.call(result, current)
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
def gather(pattern)
|
51
|
+
repeat(pattern) do |result, ch|
|
52
|
+
result << ch
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def skip_past(expected, error_message=nil)
|
57
|
+
if current == expected
|
58
|
+
advance
|
59
|
+
return expected
|
60
|
+
elsif error_message
|
61
|
+
raise error_message
|
62
|
+
end
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def skip_to_eol
|
67
|
+
until current == :eof || newline?
|
68
|
+
advance
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def skip_ws
|
73
|
+
while current != :eof
|
74
|
+
if ws?(current)
|
75
|
+
advance
|
76
|
+
elsif current == ';'
|
77
|
+
skip_to_eol
|
78
|
+
else
|
79
|
+
break
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/edn/core_ext.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module EDN
|
6
|
+
module CoreExt
|
7
|
+
module Unquoted
|
8
|
+
def to_edn
|
9
|
+
self.to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module AllowsMetadata
|
14
|
+
def allows_metadata?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Integer
|
20
|
+
def to_edn
|
21
|
+
self.to_s + 'N'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module BigDecimal
|
26
|
+
def to_edn
|
27
|
+
self.to_s('F') + 'M'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module String
|
32
|
+
def ~@
|
33
|
+
EDN::Type::Symbol.new(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_edn
|
37
|
+
array = chars.map do |ch|
|
38
|
+
if %w{" \\}.include?(ch)
|
39
|
+
'\\' + ch
|
40
|
+
else
|
41
|
+
ch
|
42
|
+
end
|
43
|
+
end
|
44
|
+
'"' + array.join + '"'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module Symbol
|
49
|
+
def to_edn
|
50
|
+
":#{self.to_s}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module Array
|
55
|
+
def ~@
|
56
|
+
EDN::Type::List.new(*self)
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_edn
|
60
|
+
'[' + self.map(&:to_edn).join(" ") + ']'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module Hash
|
65
|
+
def to_edn
|
66
|
+
'{' + self.map { |k, v| [k, v].map(&:to_edn).join(" ") }.join(", ") + '}'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module Set
|
71
|
+
def to_edn
|
72
|
+
'#{' + self.to_a.map(&:to_edn).join(" ") + '}'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module NilClass
|
77
|
+
def to_edn
|
78
|
+
"nil"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module DateTime
|
83
|
+
def to_edn
|
84
|
+
EDN.tagout("inst", self.rfc3339)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module Time
|
89
|
+
def to_edn
|
90
|
+
EDN.tagout("inst", self.xmlschema)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
Numeric.send(:include, EDN::CoreExt::Unquoted)
|
97
|
+
Integer.send(:include, EDN::CoreExt::Integer)
|
98
|
+
BigDecimal.send(:include, EDN::CoreExt::BigDecimal)
|
99
|
+
TrueClass.send(:include, EDN::CoreExt::Unquoted)
|
100
|
+
FalseClass.send(:include, EDN::CoreExt::Unquoted)
|
101
|
+
NilClass.send(:include, EDN::CoreExt::NilClass)
|
102
|
+
String.send(:include, EDN::CoreExt::String)
|
103
|
+
Symbol.send(:include, EDN::CoreExt::Symbol)
|
104
|
+
Array.send(:include, EDN::CoreExt::Array)
|
105
|
+
Hash.send(:include, EDN::CoreExt::Hash)
|
106
|
+
Set.send(:include, EDN::CoreExt::Set)
|
107
|
+
DateTime.send(:include, EDN::CoreExt::DateTime)
|
108
|
+
Time.send(:include, EDN::CoreExt::Time)
|
109
|
+
|
110
|
+
[Array, Hash, Set].each do |klass|
|
111
|
+
klass.send(:include, EDN::CoreExt::AllowsMetadata)
|
112
|
+
end
|
data/lib/edn/metadata.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module EDN
|
2
|
+
module Metadata
|
3
|
+
def self.extended(base)
|
4
|
+
base.instance_eval do
|
5
|
+
alias :to_edn_without_metadata :to_edn
|
6
|
+
alias :to_edn :to_edn_with_metadata
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :metadata
|
11
|
+
|
12
|
+
def has_metadata?
|
13
|
+
respond_to?(:allows_metadata?) and
|
14
|
+
allows_metadata? and
|
15
|
+
!metadata.nil? and
|
16
|
+
!metadata.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_edn_with_metadata
|
20
|
+
if has_metadata?
|
21
|
+
'^' + metadata.to_edn + ' ' + to_edn_without_metadata
|
22
|
+
else
|
23
|
+
to_edn_without_metadata
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|