mongo-ejson 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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