edn2023 1.1.4

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.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +29 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE +22 -0
  7. data/README.md +268 -0
  8. data/Rakefile +12 -0
  9. data/edn2023.gemspec +22 -0
  10. data/lib/edn/char_stream.rb +84 -0
  11. data/lib/edn/core_ext.rb +112 -0
  12. data/lib/edn/metadata.rb +27 -0
  13. data/lib/edn/parser.rb +92 -0
  14. data/lib/edn/reader.rb +23 -0
  15. data/lib/edn/ruby_edn_parser.rb +266 -0
  16. data/lib/edn/type/list.rb +13 -0
  17. data/lib/edn/type/symbol.rb +39 -0
  18. data/lib/edn/type/unknown.rb +9 -0
  19. data/lib/edn/type/uuid.rb +9 -0
  20. data/lib/edn/types.rb +3 -0
  21. data/lib/edn/version.rb +3 -0
  22. data/lib/edn.rb +80 -0
  23. data/spec/edn/char_stream_spec.rb +111 -0
  24. data/spec/edn/metadata_spec.rb +38 -0
  25. data/spec/edn/parser_spec.rb +162 -0
  26. data/spec/edn/reader_spec.rb +23 -0
  27. data/spec/edn_spec.rb +114 -0
  28. data/spec/exemplars/big_decimal.edn +1 -0
  29. data/spec/exemplars/big_decimal.rb +1 -0
  30. data/spec/exemplars/big_int.edn +1 -0
  31. data/spec/exemplars/big_int.rb +1 -0
  32. data/spec/exemplars/char.edn +1 -0
  33. data/spec/exemplars/char.rb +1 -0
  34. data/spec/exemplars/empty_string.edn +1 -0
  35. data/spec/exemplars/empty_string.rb +1 -0
  36. data/spec/exemplars/false.edn +1 -0
  37. data/spec/exemplars/false.rb +1 -0
  38. data/spec/exemplars/float.edn +1 -0
  39. data/spec/exemplars/float.rb +1 -0
  40. data/spec/exemplars/float_neg_exp.edn +1 -0
  41. data/spec/exemplars/float_neg_exp.rb +1 -0
  42. data/spec/exemplars/float_point_dec_neg_exp.edn +1 -0
  43. data/spec/exemplars/float_point_dec_neg_exp.rb +1 -0
  44. data/spec/exemplars/float_point_plus_exp.edn +1 -0
  45. data/spec/exemplars/float_point_plus_exp.rb +1 -0
  46. data/spec/exemplars/float_pointneg_exp.edn +1 -0
  47. data/spec/exemplars/float_pointneg_exp.rb +1 -0
  48. data/spec/exemplars/float_pos_exp.edn +1 -0
  49. data/spec/exemplars/float_pos_exp.rb +1 -0
  50. data/spec/exemplars/float_sign_exp.edn +1 -0
  51. data/spec/exemplars/float_sign_exp.rb +1 -0
  52. data/spec/exemplars/float_with_exp.edn +1 -0
  53. data/spec/exemplars/float_with_exp.rb +1 -0
  54. data/spec/exemplars/float_with_exp_no_dec.edn +1 -0
  55. data/spec/exemplars/float_with_exp_no_dec.rb +1 -0
  56. data/spec/exemplars/gt_symbol.edn +1 -0
  57. data/spec/exemplars/gt_symbol.rb +1 -0
  58. data/spec/exemplars/integer.edn +1 -0
  59. data/spec/exemplars/integer.rb +1 -0
  60. data/spec/exemplars/keyword.edn +1 -0
  61. data/spec/exemplars/keyword.rb +1 -0
  62. data/spec/exemplars/keyword_with_namespace.edn +1 -0
  63. data/spec/exemplars/keyword_with_namespace.rb +1 -0
  64. data/spec/exemplars/list_empty.edn +1 -0
  65. data/spec/exemplars/list_empty.rb +1 -0
  66. data/spec/exemplars/list_mixed.edn +1 -0
  67. data/spec/exemplars/list_mixed.rb +1 -0
  68. data/spec/exemplars/list_nested.edn +1 -0
  69. data/spec/exemplars/list_nested.rb +1 -0
  70. data/spec/exemplars/list_one_element.edn +1 -0
  71. data/spec/exemplars/list_one_element.rb +1 -0
  72. data/spec/exemplars/long_string.edn +1 -0
  73. data/spec/exemplars/long_string.rb +1 -0
  74. data/spec/exemplars/map_empty.edn +1 -0
  75. data/spec/exemplars/map_empty.rb +1 -0
  76. data/spec/exemplars/map_nested.edn +1 -0
  77. data/spec/exemplars/map_nested.rb +1 -0
  78. data/spec/exemplars/map_one_element.edn +1 -0
  79. data/spec/exemplars/map_one_element.rb +1 -0
  80. data/spec/exemplars/map_two_entry.edn +1 -0
  81. data/spec/exemplars/map_two_entry.rb +1 -0
  82. data/spec/exemplars/mmv +4 -0
  83. data/spec/exemplars/nil.edn +1 -0
  84. data/spec/exemplars/nil.rb +1 -0
  85. data/spec/exemplars/set_empty.edn +1 -0
  86. data/spec/exemplars/set_empty.rb +1 -0
  87. data/spec/exemplars/set_nested.edn +1 -0
  88. data/spec/exemplars/set_nested.rb +1 -0
  89. data/spec/exemplars/set_one_element.edn +1 -0
  90. data/spec/exemplars/set_one_element.rb +1 -0
  91. data/spec/exemplars/set_two_elements.edn +1 -0
  92. data/spec/exemplars/set_two_elements.rb +1 -0
  93. data/spec/exemplars/simple_skip.edn +1 -0
  94. data/spec/exemplars/simple_skip.rb +1 -0
  95. data/spec/exemplars/skip_more_space.edn +1 -0
  96. data/spec/exemplars/skip_more_space.rb +1 -0
  97. data/spec/exemplars/skip_more_vector_elements.edn +1 -0
  98. data/spec/exemplars/skip_more_vector_elements.rb +1 -0
  99. data/spec/exemplars/skip_some_vector_elements.edn +1 -0
  100. data/spec/exemplars/skip_some_vector_elements.rb +1 -0
  101. data/spec/exemplars/skip_two_vector_elements.edn +1 -0
  102. data/spec/exemplars/skip_two_vector_elements.rb +1 -0
  103. data/spec/exemplars/skip_vector_element.edn +1 -0
  104. data/spec/exemplars/skip_vector_element.rb +1 -0
  105. data/spec/exemplars/skip_with_spaces.edn +1 -0
  106. data/spec/exemplars/skip_with_spaces.rb +1 -0
  107. data/spec/exemplars/skip_yet_more_space.edn +1 -0
  108. data/spec/exemplars/skip_yet_more_space.rb +1 -0
  109. data/spec/exemplars/special_symbol.edn +1 -0
  110. data/spec/exemplars/special_symbol.rb +1 -0
  111. data/spec/exemplars/string_with_newline.edn +1 -0
  112. data/spec/exemplars/string_with_newline.rb +1 -0
  113. data/spec/exemplars/symbol.edn +1 -0
  114. data/spec/exemplars/symbol.rb +1 -0
  115. data/spec/exemplars/symbol_begins_with_false.edn +1 -0
  116. data/spec/exemplars/symbol_begins_with_false.rb +1 -0
  117. data/spec/exemplars/symbol_begins_with_nil.edn +1 -0
  118. data/spec/exemplars/symbol_begins_with_nil.rb +1 -0
  119. data/spec/exemplars/symbol_with_dash.edn +1 -0
  120. data/spec/exemplars/symbol_with_dash.rb +1 -0
  121. data/spec/exemplars/symbol_with_namespace.edn +1 -0
  122. data/spec/exemplars/symbol_with_namespace.rb +1 -0
  123. data/spec/exemplars/tagged_instant.edn +1 -0
  124. data/spec/exemplars/tagged_instant.rb +1 -0
  125. data/spec/exemplars/tagged_uuid.edn +1 -0
  126. data/spec/exemplars/tagged_uuid.rb +1 -0
  127. data/spec/exemplars/true.edn +1 -0
  128. data/spec/exemplars/true.rb +1 -0
  129. data/spec/exemplars/utf8.edn +1 -0
  130. data/spec/exemplars/utf8.rb +1 -0
  131. data/spec/exemplars/vector_empty.edn +1 -0
  132. data/spec/exemplars/vector_empty.rb +1 -0
  133. data/spec/exemplars/vector_mixed.edn +1 -0
  134. data/spec/exemplars/vector_mixed.rb +1 -0
  135. data/spec/exemplars/vector_nested.edn +1 -0
  136. data/spec/exemplars/vector_nested.rb +1 -0
  137. data/spec/exemplars/vector_one_element.edn +1 -0
  138. data/spec/exemplars/vector_one_element.rb +1 -0
  139. data/spec/exemplars/whole_number_with_exp.edn +1 -0
  140. data/spec/exemplars/whole_number_with_exp.rb +1 -0
  141. data/spec/spec_helper.rb +164 -0
  142. 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
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .rspec
7
+ README.html
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "2.1.0"
5
+ - "3.2.0"
6
+ - jruby-head
7
+ script: bundle exec rspec spec
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
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in edn.gemspec
4
+ gemspec
5
+
6
+
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
+ &copy; 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
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ task :irb do
10
+ sh "irb -I lib -r edn"
11
+ sh "reset"
12
+ end
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
@@ -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
@@ -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