mongo-ejson 0.2.0

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/lib/ejson.rb ADDED
@@ -0,0 +1,36 @@
1
+ require_relative '../src/ejson.rb'
2
+
3
+ require 'ejson/parser_action/abstract'
4
+ require 'ejson/parser_action/wrap'
5
+ require 'ejson/parser_action/bson'
6
+
7
+ require 'ejson/version'
8
+
9
+ class EJSON
10
+ class << self
11
+ def validate(json_string)
12
+ ExtendedJSON.parse(json_string, actions: ParserAction::Abstract)
13
+ end
14
+
15
+ def parse_bson(json_string)
16
+ boot_bson
17
+
18
+ ExtendedJSON.parse(json_string, actions: ParserAction::BSON.new)
19
+ end
20
+
21
+ def parse_wrap(json_string)
22
+ ExtendedJSON.parse(json_string, actions: ParserAction::Wrap.new)
23
+ end
24
+
25
+ private
26
+ def boot_bson
27
+ return if defined? ::BSON
28
+ require 'bson' rescue nil
29
+
30
+ unless defined? ::BSON
31
+ raise "Can't find constant ::BSON. Seems like gem 'bson' is not " \
32
+ "loaded. Make sure it's available in your bundle."
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ require 'ejson/parser_action/abstract_json'
2
+ require 'ejson/parser_action/abstract_mongo'
3
+
4
+ module ParserAction
5
+ class Abstract
6
+ include ParserAction::AbstractJSON
7
+ include ParserAction::AbstractMongo
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ module ParserAction
2
+ module AbstractJSON
3
+ # JSON Entities
4
+ def make_root(input, start, _end, elements)
5
+ end
6
+
7
+ def make_object(input, start, _end, elements)
8
+ end
9
+
10
+ def make_pair(input, start, _end, elements)
11
+ end
12
+
13
+ def make_empty_object(input, start, _end, elements)
14
+ end
15
+
16
+ def make_string(input, start, _end, elements)
17
+ end
18
+
19
+ def make_array(input, start, _end, elements)
20
+ end
21
+
22
+ def make_empty_array(input, start, _end, elements)
23
+ end
24
+
25
+ def make_number(input, start, _end, elements)
26
+ end
27
+
28
+ def make_null(input, start, _end)
29
+ end
30
+
31
+ def make_true(input, start, _end)
32
+ end
33
+
34
+ def make_false(input, start, _end)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ module ParserAction
2
+ module AbstractMongo
3
+ def make_object_id(input, start, _end, elements)
4
+ end
5
+
6
+ def make_bin_data(input, start, _end, elements)
7
+ end
8
+
9
+ def make_timestamp(input, start, _end, elements)
10
+ end
11
+
12
+ def make_number_long(input, start, _end, elements)
13
+ end
14
+
15
+ def make_number_decimal(input, start, _end, elements)
16
+ end
17
+
18
+ def make_date(input, start, _end, elements)
19
+ end
20
+
21
+ def make_regexp(input, start, _end, elements)
22
+ end
23
+
24
+ def make_db_ref(input, start, _end, elements)
25
+ end
26
+
27
+ def make_min_key(input, start, _end)
28
+ end
29
+
30
+ def make_max_key(input, start, _end)
31
+ end
32
+
33
+ def make_undefined(input, start, _end)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,61 @@
1
+ require 'ejson/parser_action/ruby'
2
+
3
+ module ParserAction
4
+ class BSON < ParserAction::Ruby
5
+ def make_object_id(input, start, _end, elements)
6
+ value = elements.first
7
+
8
+ ::BSON::ObjectId.from_string(value)
9
+ end
10
+
11
+ NUMBER_TO_TYPE = {
12
+ 0 => :generic,
13
+ 1 => :function,
14
+ 2 => :old,
15
+ 3 => :uuid_old,
16
+ 4 => :uuid,
17
+ 5 => :md5,
18
+ 128 => :user,
19
+ }
20
+
21
+ def make_bin_data(input, start, _end, elements)
22
+ data = elements.last
23
+ type = elements.first
24
+
25
+ if type.is_a? Numeric
26
+ type = NUMBER_TO_TYPE[type]
27
+ end
28
+
29
+ ::BSON::Binary.new(data, type.to_sym)
30
+ end
31
+
32
+ def make_timestamp(input, start, _end, elements)
33
+ ::BSON::Timestamp.new(elements.first, elements.last)
34
+ end
35
+
36
+ def make_number_decimal(input, start, _end, elements)
37
+ value = elements.first
38
+
39
+ ::BSON::Decimal128.new(value.to_s)
40
+ end
41
+
42
+ def make_db_ref(input, start, _end, elements)
43
+ {
44
+ "$ref": elements.first,
45
+ "$id": elements.last,
46
+ }
47
+ end
48
+
49
+ def make_min_key(input, start, _end)
50
+ ::BSON::MinKey
51
+ end
52
+
53
+ def make_max_key(input, start, _end)
54
+ ::BSON::MaxKey
55
+ end
56
+
57
+ def make_undefined(input, start, _end)
58
+ ::BSON::Undefined
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,112 @@
1
+ require 'ejson/parser_action/abstract'
2
+ require 'date'
3
+
4
+ module ParserAction
5
+ class Ruby < ParserAction::Abstract
6
+ def make_root(input, start, _end, elements)
7
+ elements.first
8
+ end
9
+
10
+ def make_object(input, start, _end, elements)
11
+ first_pair = elements.first
12
+ other_pairs = elements.last
13
+
14
+ object = {first_pair[0] => first_pair[1]}
15
+ other_pairs.each do |element|
16
+ pair = element.pair
17
+ object[pair.first] = pair.last
18
+ end
19
+
20
+ object
21
+ end
22
+
23
+ def make_pair(input, start, _end, elements)
24
+ elements
25
+ end
26
+
27
+ def make_empty_object(input, start, _end, elements)
28
+ {}
29
+ end
30
+
31
+ def make_string(input, start, _end, elements)
32
+ %Q|"#{elements.first.text}"|.undump
33
+ end
34
+
35
+ def make_numeric_string(input, start, _end, elements)
36
+ elements.first
37
+ end
38
+
39
+ def make_number_as_string(input, start, _end, elements)
40
+ string = input[start..._end]
41
+ string.downcase!
42
+
43
+ string
44
+ end
45
+
46
+ def make_array(input, start, _end, elements)
47
+ list = [elements[0]]
48
+ elements[1].each { |el| list << el.value }
49
+ list
50
+ end
51
+
52
+ def make_empty_array(input, start, _end, elements)
53
+ []
54
+ end
55
+
56
+ def make_number(input, start, _end, elements)
57
+ string = input[start..._end]
58
+ string.downcase!
59
+
60
+ _number_from_string(string)
61
+ end
62
+
63
+ def make_null(input, start, _end)
64
+ nil
65
+ end
66
+
67
+ def make_true(input, start, _end)
68
+ true
69
+ end
70
+
71
+ def make_false(input, start, _end)
72
+ false
73
+ end
74
+
75
+ # Makes ruby date from mongo Data type
76
+ def make_date(input, start, _end, elements)
77
+ value = elements.first
78
+
79
+ case value
80
+ when String
81
+ DateTime.parse(value)
82
+ when Numeric
83
+ Time.at(value)
84
+ else
85
+ raise ArgumentError,
86
+ "Internal parser error. Unknown date atom type #{value.class}"
87
+ end
88
+ end
89
+
90
+ def make_regexp(input, start, _end, elements)
91
+ Regexp.new(elements.first.text, elements.last.text)
92
+ end
93
+
94
+ def make_number_long(input, start, _end, elements)
95
+ value = elements.first
96
+ end
97
+
98
+ private
99
+
100
+ def _number_from_string(string)
101
+ if string.include? 'e'
102
+ return Float(string)
103
+ end
104
+
105
+ if string.include? '.'
106
+ string.to_f
107
+ else
108
+ string.to_i
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,44 @@
1
+ require 'ejson/parser_action/ruby'
2
+ require 'ejson/parser_action/wrap_types'
3
+ require 'bigdecimal'
4
+
5
+ module ParserAction
6
+ class Wrap < ParserAction::Ruby
7
+ def make_object_id(input, start, _end, elements)
8
+ value = elements.first
9
+
10
+ ::Wrap::ObjectId.new(value)
11
+ end
12
+
13
+ def make_bin_data(input, start, _end, elements)
14
+ data = elements.last
15
+ type = elements.first
16
+
17
+ ::Wrap::BinData.new(type, data)
18
+ end
19
+
20
+ def make_timestamp(input, start, _end, elements)
21
+ ::Wrap::Timestamp.new(elements.first, elements.last)
22
+ end
23
+
24
+ def make_number_decimal(input, start, _end, elements)
25
+ BigDecimal(elements.first)
26
+ end
27
+
28
+ def make_db_ref(input, start, _end, elements)
29
+ ::Wrap::DBRef.new(elements.first, elements.last)
30
+ end
31
+
32
+ def make_min_key(input, start, _end)
33
+ ::Wrap::MinKey
34
+ end
35
+
36
+ def make_max_key(input, start, _end)
37
+ ::Wrap::MaxKey
38
+ end
39
+
40
+ def make_undefined(input, start, _end)
41
+ ::Wrap::Undefined
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ module Wrap
2
+ MinKey = Class.new
3
+ MaxKey = Class.new
4
+ Undefined = Class.new
5
+
6
+ ObjectId = Struct.new("ObjectId", :hex)
7
+ BinData = Struct.new("BinData", :type, :data)
8
+ Timestamp = Struct.new("Timestamp", :timestamp, :fraction)
9
+
10
+ DBRef = Struct.new("DBRef", :name, :id)
11
+ end
@@ -0,0 +1 @@
1
+ require 'ejson/rails/engine'
@@ -0,0 +1,6 @@
1
+ class EJSON
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ class EJSON
2
+ VERSION = "0.2.0"
3
+ end
data/src/ejson.peg ADDED
@@ -0,0 +1,224 @@
1
+ grammar ExtendedJSON
2
+ root <- @__ (object / array) @__
3
+ %make_root
4
+
5
+ object <- (non_empty_object / empty_object)
6
+
7
+ pair <- @__ string @assignment value
8
+ %make_pair
9
+
10
+ non_empty_object <- @object_open
11
+ pair (@delimiter pair)*
12
+ @object_close
13
+ %make_object
14
+
15
+ empty_object <- @object_open
16
+ @object_close
17
+ %make_empty_object
18
+
19
+ array <- non_empty_array / empty_array
20
+
21
+ non_empty_array <- @array_open
22
+ value (@delimiter value)*
23
+ @array_close
24
+ %make_array
25
+
26
+ empty_array <- @array_open
27
+ @array_close
28
+ %make_empty_array
29
+
30
+ value <- (json_values / mongo_literals / mongo_types)
31
+
32
+ json_values <- object / array / number / string / boolean / null
33
+ mongo_literals <- min_key / max_key / undefined / regexp_string
34
+ mongo_types <- object_id / bin_data / timestamp / number_long /
35
+ number_decimal / date / db_ref_type
36
+
37
+ # Values
38
+ boolean <- (true / false)
39
+
40
+ true <- "true"
41
+ %make_true
42
+
43
+ false <- "false"
44
+ %make_false
45
+
46
+ null <- "null"
47
+ %make_null
48
+
49
+ string <- double_quote_string / single_quote_string
50
+
51
+ double_quote_string <- @double_quote
52
+ ("\\" . / [^"])*
53
+ @double_quote
54
+ %make_string
55
+
56
+ single_quote_string <- @single_quote
57
+ ("\\" . / [^'])*
58
+ @single_quote
59
+ %make_string
60
+
61
+ hex_string <- hex_single_quote / hex_double_quote
62
+ hex_value <- [a-fA-F0-9]+
63
+
64
+ hex_single_quote <- @single_quote
65
+ hex_value
66
+ @single_quote
67
+ %make_string
68
+
69
+ hex_double_quote <- @double_quote
70
+ hex_value
71
+ @double_quote
72
+ %make_string
73
+
74
+ integer_string <- integer_string_single / integer_string_double
75
+
76
+ integer_string_single <- @single_quote
77
+ integer_number
78
+ @single_quote
79
+ %make_numeric_string
80
+
81
+ integer_string_double <- @double_quote
82
+ integer_number
83
+ @double_quote
84
+ %make_numeric_string
85
+
86
+ number_string <- number_string_single / number_string_double
87
+
88
+ number_string_single <- @single_quote
89
+ number
90
+ @single_quote
91
+ %make_numeric_string
92
+
93
+ number_string_double <- @double_quote
94
+ number
95
+ @double_quote
96
+ %make_numeric_string
97
+
98
+ regexp_string <- @slash
99
+ ("\\" . / [^\/])*
100
+ @slash
101
+ regexp_options?
102
+ %make_regexp
103
+
104
+ regexp_options <- [gims]+
105
+
106
+ base64_string <- base64_single_quote / base64_dobule_quote
107
+
108
+ base64_value <- [a-zA-Z0-9+\/]+ ("=" / "==")?
109
+
110
+ base64_single_quote <- @single_quote
111
+ base64_value
112
+ @single_quote
113
+ %make_string
114
+
115
+ base64_dobule_quote <- @double_quote
116
+ base64_value
117
+ @double_quote
118
+ %make_string
119
+
120
+ number <- "-"? integer fraction? exponent?
121
+ %make_number
122
+
123
+ number_as_string <- "-"? integer fraction? exponent?
124
+ %make_number_as_string
125
+
126
+ integer <- ("0" / [1-9] [0-9]*)
127
+ fraction <- ("." [0-9]+)
128
+ exponent <- (("e" / "E") ("+" / "-" / "") [0-9]+)
129
+
130
+ integer_number <- integer @""
131
+ %make_number
132
+
133
+ # Mongo Extensions
134
+
135
+ min_key <- "MinKey"
136
+ %make_min_key
137
+
138
+ max_key <- "MaxKey"
139
+ %make_max_key
140
+
141
+ undefined <- "undefined"
142
+ %make_undefined
143
+
144
+ object_id <- @"ObjectId"
145
+ @type_open
146
+ hex_string
147
+ @type_close
148
+ %make_object_id
149
+
150
+ bin_data_type <- string / integer_number
151
+ bin_data <- @"BinData"
152
+ @type_open
153
+ bin_data_type
154
+ @delimiter
155
+ base64_string
156
+ @type_close
157
+ %make_bin_data
158
+
159
+ timestamp <- @"Timestamp"
160
+ @type_open
161
+ integer_number
162
+ @delimiter
163
+ integer_number
164
+ @type_close
165
+ %make_timestamp
166
+
167
+ number_long_value <- integer_number / integer_string
168
+ number_long <- @"NumberLong"
169
+ @type_open
170
+ number_long_value
171
+ @type_close
172
+ %make_number_long
173
+
174
+
175
+ number_decimal_value <- number_as_string / number_string
176
+ number_decimal <- @"NumberDecimal"
177
+ @type_open
178
+ number_decimal_value
179
+ @type_close
180
+ %make_number_decimal
181
+
182
+ date_type <- ("new" space+ "Date" / "ISODate")
183
+ date_value <- integer_number / string
184
+ date <- @date_type
185
+ @type_open
186
+ date_value
187
+ @type_close
188
+ %make_date
189
+
190
+ db_ref_type <- @"DBRef"
191
+ @type_open
192
+ string
193
+ @delimiter
194
+ string
195
+ @type_close
196
+ %make_db_ref
197
+
198
+ single_quote <- "'"
199
+ double_quote <- '"'
200
+ left_paren <- '('
201
+ right_paren <- ')'
202
+ left_brace <- '{'
203
+ right_brace <- '}'
204
+ left_bracket <- '['
205
+ right_bracket <- ']'
206
+ comma <- ','
207
+ colon <- ':'
208
+ slash <- '/'
209
+ space <- [\s]
210
+ new_line <- [\n]
211
+
212
+ comment <- "//" [^\n]*
213
+ __ <- (space / new_line / comment)*
214
+
215
+ delimiter <- @__ comma @__
216
+ assignment <- @__ @colon @__
217
+
218
+ object_open <- @__ @left_brace @__
219
+ object_close <- @__ @right_brace @__
220
+ array_open <- @__ @left_bracket @__
221
+ array_close <- @__ @right_bracket @__
222
+
223
+ type_open <- @space* @left_paren @space*
224
+ type_close <- @space* @right_paren