ruby_token_parser 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2c60c4b936d34a0388136c3585afa1726b580b256b7bb277f1323706a5bbe4e0
4
+ data.tar.gz: 1de41610a7b060f7ded20bd3e1d953fb6e86b21de47e01747364a7a2ce8e9364
5
+ SHA512:
6
+ metadata.gz: 72ce6264df8b2154cfbe423a03d30b2972b57f05f096ec438c45a0de41057bf58a6efc0f23a4db74f09d6cd7013376104c5b4fb59c99ab759751f88277abda7e
7
+ data.tar.gz: 763aed054956357e20b6b983fff7e8e00ce22d466e41e421da63d7b2e1dea80d8925dc8363ed028da9d3ea6fe9097de0efce9c8190b8a7ee6a696d182965efb0
@@ -0,0 +1,27 @@
1
+ Original Copyright (c) 2012-2014, Stefan Rusterholz <stefan.rusterholz@gmail.com>
2
+
3
+ Derived work Copyright (c) 2015, "shevy" Robert A. Heiler <shevegen@gmail.com>
4
+
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without modification,
8
+ are permitted provided that the following conditions are met:
9
+
10
+ Redistributions of source code must retain the above copyright notice,
11
+ this list of conditions and the following disclaimer.
12
+
13
+ Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,107 @@
1
+ README
2
+ ======
3
+
4
+
5
+ Summary
6
+ -------
7
+
8
+ This project, called ruby_token_parser, will parse strings containing
9
+ ruby literals and return a proper ruby object.
10
+
11
+ This can be used to deconstruct a String into its constituent members
12
+ as valid ruby objects, similar as to what IRB is doing when you let
13
+ it evaluate the user input you supply it with.
14
+
15
+
16
+ Features
17
+ --------
18
+
19
+ * Recognizes about all Ruby literals:
20
+
21
+ nil, true, false, Symbols, Integers, Floats, Hashes, Arrays and
22
+ also Ranges.
23
+
24
+ * Additionally parses Constants, Dates and Times.
25
+
26
+ * Simple to use through [] or .parse such as:
27
+
28
+ RubyTokenParser[]
29
+
30
+ Installation
31
+ ------------
32
+
33
+ `gem install ruby_token_parser`
34
+
35
+
36
+ Usage
37
+ -----
38
+
39
+ Several examples follow next:
40
+
41
+ RubyTokenParser.parse("nil") # => nil
42
+ RubyTokenParser.parse(":foo") # => :foo
43
+ RubyTokenParser.parse("123") # => 123
44
+ RubyTokenParser.parse("1.5") # => 1.5
45
+ RubyTokenParser.parse("1.5", use_big_decimal: true) # => #<BigDecimal:…,'0.15E1',18(18)>
46
+ RubyTokenParser.parse("[1, 2, 3]") # => [1, 2, 3]
47
+ RubyTokenParser.parse("{:a => 1, :b => 2}") # => {:a => 1, :b => 2}
48
+ RubyTokenParser.parse("(1..15)")
49
+ RubyTokenParser["(1..15)"]
50
+
51
+
52
+ License
53
+ -------
54
+
55
+ You can use this code under the {file:LICENSE.txt BSD-2-Clause License},
56
+ free of charge.
57
+
58
+ A link to the content of this license is provided here:
59
+
60
+ https://opensource.org/licenses/BSD-2-Clause
61
+
62
+ Note that the original version of this gem, called "literal_parser",
63
+ was written by apeiros (Stefan Rusterholz) - you may be able to find
64
+ his work here at:
65
+
66
+ https://github.com/apeiros
67
+ https://github.com/apeiros/literal_parser
68
+
69
+ If you need a different license in regards to the original literal_parser,
70
+ please ask apeiros, not me, since it was his original code and work.
71
+
72
+ My (shevy) modifications were small, mostly just cosmetic, some renaming,
73
+ the addition of Range-objects (since I needed that in one other project
74
+ specifically), a bit more documentation, a general restructure of the
75
+ code to make it easier for me to read and the addition of [] as a class
76
+ method.
77
+
78
+ The BSD-2 license mandates that one has to retain the original copyright.
79
+
80
+ I assume that the original copyright is the following one here:
81
+
82
+ Copyright (c) 2012-2014, apeiros (Stefan Rusterholz)
83
+
84
+ The link to that license can be found at:
85
+
86
+ https://github.com/apeiros/literal_parser/blob/master/LICENSE.txt
87
+
88
+ Or respectively as part of apeiros' literal_parser project.
89
+
90
+ This LICENSE.txt is also part of the gem here and was included in
91
+ the literal_parser project.
92
+
93
+ I will add the disclaimer as part of the license link to the readme
94
+ here, as the original link at opensource.org also states something
95
+ somewhat similar:
96
+
97
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
98
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
99
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
100
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
101
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
102
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
103
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
104
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
105
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
106
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
107
+ THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ require 'ruby_token_parser/ruby_token_parser.rb'
@@ -0,0 +1,74 @@
1
+ class RubyTokenParser
2
+
3
+ # ========================================================================= #
4
+ # === RubyTokenParser.parse
5
+ #
6
+ # The RubyTokenParser.parse() method will parse a String, and return
7
+ # the (ruby) object which it contains.
8
+ #
9
+ # @usage example:
10
+ #
11
+ # RubyTokenParser.parse(":foo") # => :foo
12
+ #
13
+ # @param [String] string
14
+ #
15
+ # The (input) String which should be parsed.
16
+ #
17
+ # @param [nil, Hash] options
18
+ #
19
+ # An options-hash
20
+ #
21
+ # @param [Boolean] do_raise_an_exception
22
+ #
23
+ # This boolean will determine whether we will raise an exception
24
+ # or whether we will not.
25
+ #
26
+ # @option options [Boolean] :use_big_decimal
27
+ #
28
+ # Whether to use BigDecimal instead of Float for objects like "1.23".
29
+ # Defaults to false.
30
+ #
31
+ # @option options [Boolean] :constant_base
32
+ #
33
+ # Determines from what constant other constants are searched.
34
+ # Defaults to Object (nil is treated as Object too, Object
35
+ # is the toplevel-namespace).
36
+ #
37
+ # @return [Object] The object in the string.
38
+ #
39
+ # @raise [RubyTokenParser::SyntaxError]
40
+ #
41
+ # If the String does not contain exactly one valid literal,
42
+ # a SyntaxError is raised.
43
+ #
44
+ # Usage example:
45
+ # x = RubyTokenParser.parse("[1,2,3]")
46
+ # ========================================================================= #
47
+ def self.parse(
48
+ string,
49
+ options = nil,
50
+ do_raise_an_exception = RubyTokenParser.raise_exception?
51
+ )
52
+ # ======================================================================= #
53
+ # === Instantiate a new parser
54
+ # ======================================================================= #
55
+ parser = new(string, options)
56
+ begin
57
+ value = parser.scan_value
58
+ rescue RubyTokenParser::SyntaxError # Must rescue things such as: @foo = foo
59
+ value = RubyTokenParser::SyntaxError
60
+ end
61
+ if do_raise_an_exception
62
+ unless parser.end_of_string? or
63
+ value.nil?
64
+ # =================================================================== #
65
+ # Raise the Syntax Error.
66
+ # =================================================================== #
67
+ raise SyntaxError,
68
+ "Unexpected superfluous data: #{parser.rest.inspect}"
69
+ end unless value.is_a? Range # Make an exception for Range objects.
70
+ end
71
+ value
72
+ end; self.instance_eval { alias [] parse } # === RubyTokenParser[]
73
+ # ^^^ Add an alias to it, aka [].
74
+ end
@@ -0,0 +1,5 @@
1
+ require 'strscan'
2
+ require 'bigdecimal'
3
+ require 'date'
4
+ require 'ruby_token_parser/ruby_token_constants.rb'
5
+ require 'ruby_token_parser/parse.rb'
@@ -0,0 +1,188 @@
1
+ class RubyTokenParser
2
+
3
+ # ========================================================================= #
4
+ # === RubyTokenParser::Expressions
5
+ #
6
+ # @private
7
+ #
8
+ # All the expressions used to parse the literals will be bundled here.
9
+ # ========================================================================= #
10
+ module Expressions # === RubyTokenParser::Expressions
11
+
12
+ # ======================================================================= #
13
+ # === Match to the start of an Array
14
+ # ======================================================================= #
15
+ RArrayBegin = /\[/
16
+
17
+ # ======================================================================= #
18
+ # === Match whitespace between elements in an Array
19
+ # ======================================================================= #
20
+ RArrayVoid = /\s*/
21
+
22
+ # ======================================================================= #
23
+ # === Match the separator of Array elements
24
+ #
25
+ # This depends on RArrayVoid having been defined before.
26
+ #
27
+ # A separator in an Array is something such as:
28
+ # [1,2,3]
29
+ # ======================================================================= #
30
+ RArraySeparator = /#{RArrayVoid},#{RArrayVoid}/
31
+
32
+ # ======================================================================= #
33
+ # === Match to the end of an Array
34
+ # ======================================================================= #
35
+ RArrayEnd = /\]/
36
+
37
+ # ======================================================================= #
38
+ # === Match to the start of a Hash
39
+ # ======================================================================= #
40
+ RHashBegin = /\{/
41
+
42
+ # ======================================================================= #
43
+ # === Match whitespace between elements in a Hash
44
+ # ======================================================================= #
45
+ RHashVoid = /\s*/
46
+
47
+ # ======================================================================= #
48
+ # === Match the separator of hash key/value pairs
49
+ # ======================================================================= #
50
+ RHashSeparator = /#{RHashVoid},#{RHashVoid}/
51
+
52
+ # ======================================================================= #
53
+ # === Match the separator between a key and a value in a hash
54
+ # ======================================================================= #
55
+ RHashArrow = /#{RHashVoid}=>#{RHashVoid}/
56
+
57
+ # ======================================================================= #
58
+ # === Match end of a Hash
59
+ # ======================================================================= #
60
+ RHashEnd = /\}/
61
+
62
+ # ======================================================================= #
63
+ # === Match constant names (with nesting)
64
+ # ======================================================================= #
65
+ RConstant = /[A-Z]\w*(?:::[A-Z]\w*)*/
66
+
67
+ # ======================================================================= #
68
+ # === Match to nil
69
+ # ======================================================================= #
70
+ RNil = /nil/
71
+
72
+ # ======================================================================= #
73
+ # === Match false
74
+ # ======================================================================= #
75
+ RFalse = /false/
76
+
77
+ # ======================================================================= #
78
+ # === Match true
79
+ # ======================================================================= #
80
+ RTrue = /true/
81
+
82
+ # ======================================================================= #
83
+ # === Match an Integer in decimal notation
84
+ # ======================================================================= #
85
+ RInteger = /[+-]?\d[\d_]*/
86
+
87
+ # ======================================================================= #
88
+ # === Match an Integer in binary notation
89
+ # ======================================================================= #
90
+ RBinaryInteger = /[+-]?0b[01][01_]*/
91
+
92
+ # ======================================================================= #
93
+ # === Match an Integer in hexadecimal notation
94
+ # ======================================================================= #
95
+ RHexInteger = /[+-]?0x[A-Fa-f\d][A-Fa-f\d_]*/
96
+
97
+ # ======================================================================= #
98
+ # === Match a decimal number (Float or BigDecimal)
99
+ # ======================================================================= #
100
+ RBigDecimal = /#{RInteger}\.\d+/
101
+
102
+ # ======================================================================= #
103
+ # === Match a decimal number in scientific notation
104
+ # ======================================================================= #
105
+ RFloat = /#{RBigDecimal}(?:f|e#{RInteger})/
106
+
107
+ # ======================================================================= #
108
+ # === Match a date
109
+ # ======================================================================= #
110
+ RDate = /(\d{4})-(\d{2})-(\d{2})/
111
+
112
+ # ======================================================================= #
113
+ # === Match a time (without date)
114
+ # ======================================================================= #
115
+ RTime = /(\d{2}):(\d{2}):(\d{2})(?:RTimeZone)?/
116
+
117
+ # ======================================================================= #
118
+ # === Match a datetime (must come after RTime was defined)
119
+ # ======================================================================= #
120
+ RDateTime = /#{RDate}T#{RTime}/
121
+
122
+ # ======================================================================= #
123
+ # === Match a regular expression
124
+ # ======================================================================= #
125
+ RRegexp = %r{/((?:[^\\/]+|\\.)*)/([imxnNeEsSuU]*)}
126
+
127
+ # ======================================================================= #
128
+ # === Match a double quoted string.
129
+ # ======================================================================= #
130
+ RDString = /"(?:[^\\"]+|\\.)*"/
131
+
132
+ # ======================================================================= #
133
+ # === Match a single quoted string.
134
+ # ======================================================================= #
135
+ RSString = /'(?:[^\\']+|\\.)*'/
136
+
137
+ # ======================================================================= #
138
+ # === Match a symbol (symbol tag)
139
+ #
140
+ # Note that this depends on RSString and RDString, so these
141
+ # must come before that.
142
+ # ======================================================================= #
143
+ RSymbol = /:[A-Za-z_]\w*|:#{RSString}|:#{RDString}/
144
+
145
+ # ======================================================================= #
146
+ # === Match a symbol used as key in a Hash
147
+ # ======================================================================= #
148
+ RHashKeySymbol = /([A-Za-z_]\w*):/
149
+
150
+ # ======================================================================= #
151
+ # === Match a timezone
152
+ # ======================================================================= #
153
+ RTimeZone = /(Z|[A-Z]{3,4}|[+-]\d{4})/
154
+
155
+ # ======================================================================= #
156
+ # === Match a Regex such as (1..5)
157
+ # ======================================================================= #
158
+ RRange = /\(\d*..\d*\)/
159
+
160
+ # ======================================================================= #
161
+ # === Match an Integer in octal notation
162
+ # ======================================================================= #
163
+ ROctalInteger = /[+-]?0[0-7][0-7'_,]*/
164
+
165
+ # ======================================================================= #
166
+ # === DoubleQuotedStringEscapes
167
+ #
168
+ # Map escape sequences in double quoted strings.
169
+ #
170
+ # This will be a really huge Hash.
171
+ # ======================================================================= #
172
+ DoubleQuotedStringEscapes = {
173
+ '\\\\' => "\\",
174
+ "\\'" => "'",
175
+ '\\"' => '"',
176
+ '\t' => "\t",
177
+ '\f' => "\f",
178
+ '\r' => "\r",
179
+ '\n' => "\n",
180
+ }
181
+ 256.times { |i|
182
+ DoubleQuotedStringEscapes["\\%o" % i] = i.chr
183
+ DoubleQuotedStringEscapes["\\%03o" % i] = i.chr
184
+ DoubleQuotedStringEscapes["\\x%02x" % i] = i.chr
185
+ DoubleQuotedStringEscapes["\\x%02X" % i] = i.chr
186
+ }
187
+
188
+ end; end
@@ -0,0 +1,438 @@
1
+ #!/System/Index/bin/ruby -w
2
+ # Encoding: ISO-8859-1
3
+ # =========================================================================== #
4
+ # === RubyTokenParser
5
+ #
6
+ # require 'ruby_token_parser'; x = RubyTokenParser.parse("(1..3)")
7
+ # require 'ruby_token_parser'; x = RubyTokenParser.parse("[1,2,3]")
8
+ # require 'ruby_token_parser'; RubyTokenParser["(1..3)"]
9
+ # =========================================================================== #
10
+ require 'ruby_token_parser/requires.rb'
11
+
12
+ # =========================================================================== #
13
+ # === RubyTokenParser
14
+ #
15
+ # Parse Strings containing ruby literals.
16
+ #
17
+ # @examples
18
+ #
19
+ # RubyTokenParser.parse("nil") # => nil
20
+ # RubyTokenParser.parse(":foo") # => :foo
21
+ # RubyTokenParser.parse("123") # => 123
22
+ # RubyTokenParser.parse("1.5") # => 1.5
23
+ # RubyTokenParser.parse("1.5", use_big_decimal: true) # => #<BigDecimal:…,'0.15E1',18(18)>
24
+ # RubyTokenParser.parse("[1, 2, 3]") # => [1, 2, 3]
25
+ # RubyTokenParser.parse("{:a => 1, :b => 2}") # => {:a => 1, :b => 2}
26
+ # RubyTokenParser.parse("(1..3)")
27
+ #
28
+ # RubyTokenParser recognizes constants and the following literals:
29
+ #
30
+ # nil # nil
31
+ # true # true
32
+ # false # false
33
+ # -123 # Fixnum/Bignum (decimal)
34
+ # 0b1011 # Fixnum/Bignum (binary)
35
+ # 0755 # Fixnum/Bignum (octal)
36
+ # 0xff # Fixnum/Bignum (hexadecimal)
37
+ # 120.30 # Float (optional: BigDecimal)
38
+ # 1e0 # Float
39
+ # "foo" # String, no interpolation, but \t etc. work
40
+ # 'foo' # String, only \\ and \' are escaped
41
+ # /foo/ # Regexp
42
+ # :foo # Symbol
43
+ # :"foo" # Symbol
44
+ # 2012-05-20 # Date
45
+ # 2012-05-20T18:29:52 # DateTime
46
+ # [Any, Literals, Here] # Array
47
+ # {Any => Literals} # Hash
48
+ # (1..20) # Range
49
+ #
50
+ # @note Limitations
51
+ #
52
+ # * RubyTokenParser does not support ruby 1.9's `{key: value}` syntax.
53
+ # * RubyTokenParser does not currently support all of rubys escape
54
+ # sequences in strings and symbols.
55
+ # * Trailing commas in Array and Hash are not supported.
56
+ #
57
+ # @note BigDecimals
58
+ #
59
+ # You can instruct RubyTokenParser to parse "12.5" as a bigdecimal
60
+ # and use "12.5e" to have it parsed as float (short for "12.5e0",
61
+ # equivalent to "1.25e1")
62
+ #
63
+ # @note Date & Time
64
+ #
65
+ # RubyTokenParser supports a subset of ISO-8601 for Date and Time which
66
+ # are not actual valid ruby literals. The form YYYY-MM-DD (e.g. 2012-05-20)
67
+ # is translated to a Date object, and YYYY-MM-DD"T"HH:MM:SS (e.g.
68
+ # 2012-05-20T18:29:52) is translated to a Time object.
69
+ # =========================================================================== #
70
+ class RubyTokenParser
71
+
72
+ include RubyTokenParser::Expressions
73
+
74
+ # ========================================================================= #
75
+ # === @do_raise_exception
76
+ # ========================================================================= #
77
+ @do_raise_exception = true
78
+
79
+ # ========================================================================= #
80
+ # === RubyTokenParser.set_do_raise_exception
81
+ # ========================================================================= #
82
+ def self.set_do_raise_exception(i = true)
83
+ @do_raise_exception = i
84
+ end
85
+
86
+ # ========================================================================= #
87
+ # === RubyTokenParser.raise_exception?
88
+ # ========================================================================= #
89
+ def self.raise_exception?
90
+ @do_raise_exception
91
+ end
92
+
93
+ # ========================================================================= #
94
+ # === RubyTokenParser::SyntaxError
95
+ #
96
+ # This error is raised when a String could not be parsed.
97
+ # ========================================================================= #
98
+ class SyntaxError < StandardError; end
99
+
100
+ # ========================================================================= #
101
+ # === initialize
102
+ #
103
+ # Parse a String, returning the object which it contains.
104
+ #
105
+ # @param [String] string
106
+ # The string which should be parsed
107
+ #
108
+ # @param [nil, Hash] options
109
+ # An options-hash
110
+ #
111
+ # @option options [Boolean] :use_big_decimal
112
+ # Whether to use BigDecimal instead of Float for objects like "1.23".
113
+ # Defaults to false.
114
+ #
115
+ # @option options [Boolean] :constant_base
116
+ #
117
+ # Determines from what constant other constants are searched.
118
+ #
119
+ # Defaults to Object (nil is treated as Object too, Object
120
+ # is the toplevel-namespace).
121
+ # ========================================================================= #
122
+ def initialize(string, options = nil)
123
+ @string = string
124
+ options = options ? options.dup : {}
125
+ @constant_base = options[:constant_base] # nil means toplevel
126
+ @use_big_decimal = options.delete(:use_big_decimal) { false }
127
+ @scanner = StringScanner.new(string)
128
+ end
129
+
130
+ # ========================================================================= #
131
+ # === position?
132
+ #
133
+ # @return [Integer]
134
+ #
135
+ # The position of the scanner in the string.
136
+ # ========================================================================= #
137
+ def position?
138
+ @scanner.pos
139
+ end; alias position position? # === position
140
+
141
+ # ========================================================================= #
142
+ # === position=
143
+ #
144
+ # Moves the scanners position to the given character-index.
145
+ #
146
+ # @param [Integer] value
147
+ #
148
+ # The new position of the scanner
149
+ # ========================================================================= #
150
+ def position=(i)
151
+ @scanner.pos = i
152
+ end
153
+
154
+ # ========================================================================= #
155
+ # === end_of_string?
156
+ #
157
+ # @return [Boolean]
158
+ #
159
+ # Whether the scanner reached the end of the string.
160
+ # ========================================================================= #
161
+ def end_of_string?
162
+ @scanner.eos?
163
+ end
164
+
165
+ # ========================================================================= #
166
+ # === rest
167
+ #
168
+ # @return [String] The currently unprocessed rest of the string.
169
+ # ========================================================================= #
170
+ def rest
171
+ @scanner.rest
172
+ end
173
+
174
+ # ========================================================================= #
175
+ # === content?
176
+ #
177
+ # Reader method over the current value of the scanner.
178
+ # ========================================================================= #
179
+ def content?
180
+ @scanner.string
181
+ end
182
+
183
+ # ========================================================================= #
184
+ # === use_big_decimal?
185
+ #
186
+ # @return [Boolean]
187
+ #
188
+ # True if "1.25" should be parsed into a big-decimal,
189
+ # false if it should be parsed as Float.
190
+ # ========================================================================= #
191
+ def use_big_decimal?
192
+ @use_big_decimal
193
+ end; alias use_big_decimal use_big_decimal? # === use_big_decimal
194
+
195
+ # ========================================================================= #
196
+ # === inspect?
197
+ # ========================================================================= #
198
+ def inspect?
199
+ @scanner.rest.inspect
200
+ end
201
+
202
+ # ========================================================================= #
203
+ # === constant_base?
204
+ #
205
+ # @return [Module, nil]
206
+ #
207
+ # Where to lookup constants. Nil is toplevel (equivalent to Object).
208
+ # ========================================================================= #
209
+ def constant_base?
210
+ @constant_base
211
+ end; alias constant_base constant_base? # === constant_base
212
+
213
+ # ========================================================================= #
214
+ # === scan_value
215
+ #
216
+ # Scans the string for a single value and advances the parsers position.
217
+ #
218
+ # @return [Object] the scanned value
219
+ #
220
+ # @raise [RubyTokenParser::SyntaxError]
221
+ #
222
+ # When no valid ruby object could be scanned at the given position,
223
+ # a RubyTokenParser::SyntaxError is raised. Alternative you can
224
+ # disable raising an error by calling:
225
+ #
226
+ # RubyTokenParser.set_do_raise_exception(false)
227
+ #
228
+ # ========================================================================= #
229
+ def scan_value
230
+ case
231
+ # ======================================================================= #
232
+ # === Handle Ranges (range tag, ranges tag)
233
+ # ======================================================================= #
234
+ when (!content?.scan(RRange).empty?)
235
+ _ = content?.delete('(').delete(')').squeeze('.').split('.').map(&:to_i)
236
+ min = _.first
237
+ max = _.last
238
+ Range.new(min, max)
239
+ # ======================================================================= #
240
+ # === Handle Arrays (arrays tag, array tag)
241
+ # ======================================================================= #
242
+ when @scanner.scan(RArrayBegin)
243
+ value = []
244
+ @scanner.scan(RArrayVoid)
245
+ if @scanner.scan(RArrayEnd)
246
+ value
247
+ else
248
+ value << scan_value
249
+ while @scanner.scan(RArraySeparator)
250
+ value << scan_value
251
+ end
252
+ unless @scanner.scan(RArrayVoid) && @scanner.scan(RArrayEnd)
253
+ raise SyntaxError, 'Expected ]'
254
+ end
255
+ value
256
+ end
257
+ # ======================================================================= #
258
+ # === Handle Hashes
259
+ #
260
+ # This is quite complicated. We have to scan whether we may find
261
+ # the {} syntax or the end of a hash.
262
+ # ======================================================================= #
263
+ when @scanner.scan(RHashBegin)
264
+ value = {}
265
+ @scanner.scan(RHashVoid)
266
+ if @scanner.scan(RHashEnd)
267
+ value
268
+ else
269
+ if @scanner.scan(RHashKeySymbol)
270
+ key = @scanner[1].to_sym
271
+ @scanner.scan(RHashVoid)
272
+ else
273
+ key = scan_value
274
+ unless @scanner.scan(RHashArrow)
275
+ raise SyntaxError, 'Expected =>'
276
+ end
277
+ end
278
+ val = scan_value
279
+ value[key] = val
280
+ while @scanner.scan(RHashSeparator)
281
+ if @scanner.scan(RHashKeySymbol)
282
+ key = @scanner[1].to_sym
283
+ @scanner.scan(RHashVoid)
284
+ else
285
+ key = scan_value
286
+ raise SyntaxError, 'Expected =>' unless @scanner.scan(RHashArrow)
287
+ end
288
+ val = scan_value
289
+ value[key] = val
290
+ end
291
+ unless @scanner.scan(RHashVoid) && @scanner.scan(RHashEnd)
292
+ raise SyntaxError, 'Expected }'
293
+ end
294
+ value
295
+ end
296
+ # ======================================================================= #
297
+ # === Handle Constants
298
+ #
299
+ # eval() is evil but it may be sane due to the regex, also
300
+ # it's less annoying than deep_const_get.
301
+ #
302
+ # @constant_base can be set via the Hash options[:constant_base].
303
+ # ======================================================================= #
304
+ when @scanner.scan(RConstant)
305
+ eval("#{@constant_base}::#{@scanner.first}")
306
+ # ======================================================================= #
307
+ # === Handle Nil values
308
+ # ======================================================================= #
309
+ when @scanner.scan(RNil)
310
+ nil
311
+ # ======================================================================= #
312
+ # === Handle True values
313
+ # ======================================================================= #
314
+ when @scanner.scan(RTrue) # true tag
315
+ true
316
+ # ======================================================================= #
317
+ # === Handle False values
318
+ # ======================================================================= #
319
+ when @scanner.scan(RFalse) # false tag
320
+ false
321
+ # ======================================================================= #
322
+ # === Handle DateTime values
323
+ # ======================================================================= #
324
+ when @scanner.scan(RDateTime)
325
+ Time.mktime( # Tap into the regex pattern next.
326
+ @scanner[1], @scanner[2],
327
+ @scanner[3], @scanner[4],
328
+ @scanner[5], @scanner[6]
329
+ )
330
+ # ======================================================================= #
331
+ # === Handle Date values
332
+ # ======================================================================= #
333
+ when @scanner.scan(RDate)
334
+ date = @scanner[1].to_i, @scanner[2].to_i, @scanner[3].to_i
335
+ Date.civil(*date)
336
+ # ======================================================================= #
337
+ # === Handle RTime values
338
+ # ======================================================================= #
339
+ when @scanner.scan(RTime)
340
+ now = Time.now
341
+ Time.mktime(
342
+ now.year, now.month, now.day,
343
+ @scanner[1].to_i, @scanner[2].to_i, @scanner[3].to_i
344
+ )
345
+ # ======================================================================= #
346
+ # === Handle Float values
347
+ # ======================================================================= #
348
+ when @scanner.scan(RFloat)
349
+ Float(@scanner.matched.delete('^0-9.e-'))
350
+ # ======================================================================= #
351
+ # === Handle BigDecimal values
352
+ # ======================================================================= #
353
+ when @scanner.scan(RBigDecimal)
354
+ data = @scanner.matched.delete('^0-9.-')
355
+ @use_big_decimal ? BigDecimal(data) : Float(data)
356
+ # ======================================================================= #
357
+ # === Handle OctalInteger values
358
+ # ======================================================================= #
359
+ when @scanner.scan(ROctalInteger)
360
+ # ===================================================================== #
361
+ # We can make use of Integer to turn them into valid ruby objects.
362
+ # ===================================================================== #
363
+ Integer(@scanner.matched.delete('^0-9-'))
364
+ # ======================================================================= #
365
+ # === Handle HexInteger values
366
+ # ======================================================================= #
367
+ when @scanner.scan(RHexInteger)
368
+ Integer(@scanner.matched.delete('^xX0-9A-Fa-f-'))
369
+ # ======================================================================= #
370
+ # === Handle BinaryInteger values
371
+ # ======================================================================= #
372
+ when @scanner.scan(RBinaryInteger)
373
+ Integer(@scanner.matched.delete('^bB01-'))
374
+ # ======================================================================= #
375
+ # === Handle Integer values
376
+ # ======================================================================= #
377
+ when @scanner.scan(RInteger)
378
+ @scanner.matched.delete('^0-9-').to_i
379
+ # ======================================================================= #
380
+ # === Handle Regexp values
381
+ # ======================================================================= #
382
+ when @scanner.scan(RRegexp)
383
+ source = @scanner[1]
384
+ flags = 0
385
+ lang = nil
386
+ if @scanner[2]
387
+ flags |= Regexp::IGNORECASE if @scanner[2].include?('i') # Value of 1
388
+ flags |= Regexp::EXTENDED if @scanner[2].include?('m') # Value of 2
389
+ flags |= Regexp::MULTILINE if @scanner[2].include?('x') # Value of true
390
+ lang = @scanner[2].delete('^nNeEsSuU')[-1,1]
391
+ end
392
+ Regexp.new(source, flags, lang)
393
+ # ======================================================================= #
394
+ # === Handle double-quoted string values
395
+ # ======================================================================= #
396
+ when @scanner.scan(RDString)
397
+ @scanner.matched[1..-2].gsub(/\\(?:[0-3]?\d\d?|x[A-Fa-f\d]{2}|.)/) { |m|
398
+ DStringEscapes[m]
399
+ }
400
+ # ======================================================================= #
401
+ # === Handle Symbol values (symbol tag, symbols tag)
402
+ # ======================================================================= #
403
+ when @scanner.scan(RSymbol)
404
+ # ===================================================================== #
405
+ # Next, check the first character matched.
406
+ # ===================================================================== #
407
+ case @scanner.matched[1,1] # Might be "f".
408
+ # ===================================================================== #
409
+ # If it is a '"' quote, enter here.
410
+ # ===================================================================== #
411
+ when '"'
412
+ @scanner.matched[2..-2].gsub(/\\(?:[0-3]?\d\d?|x[A-Fa-f\d]{2}|.)/) { |m|
413
+ DStringEscapes[m]
414
+ }.to_sym
415
+ # ===================================================================== #
416
+ # If it is a "'" quote, enter here.
417
+ # ===================================================================== #
418
+ when "'"
419
+ @scanner.matched[2..-2].gsub(/\\'/, "'").gsub(/\\\\/, "\\").to_sym
420
+ else # Default here. Match all but the leading ':'
421
+ @scanner.matched[1..-1].to_sym
422
+ end
423
+ # ======================================================================= #
424
+ # === Handle single-quoted string values
425
+ # ======================================================================= #
426
+ when @scanner.scan(RSString)
427
+ @scanner.matched[1..-2].gsub(/\\'/, "'").gsub(/\\\\/, "\\")
428
+ # ======================================================================= #
429
+ # === Handle everything else
430
+ #
431
+ # This can lead to a runtime error, so we must raise a SyntaxError.
432
+ # ======================================================================= #
433
+ else # else tag
434
+ raise SyntaxError, "Unrecognized pattern: #{inspect?}"
435
+ end
436
+ end
437
+
438
+ end
@@ -0,0 +1,49 @@
1
+ # =========================================================================== #
2
+ # Gemspec for Project RubyTokenParser.
3
+ # =========================================================================== #
4
+ Gem::Specification.new { |s|
5
+
6
+ s.name = 'ruby_token_parser'
7
+ s.version = '0.0.6'
8
+ s.date = Time.now.strftime('%Y-%m-%d')
9
+
10
+ DESCRIPTION = <<-EOF
11
+
12
+ This project is called ruby_token_parser.
13
+
14
+ It allows one to parse for ruby literals, which can
15
+ be used to return a proper ruby object.
16
+
17
+ This project is based on apeiros' prior work, his gem
18
+ is called literal_parser - check it out.
19
+
20
+ If you have specific suggestions to make this gem more
21
+ useful for others, please drop me an email at:
22
+
23
+ shevegen@gmail.com
24
+
25
+ Thank you.
26
+ EOF
27
+
28
+ s.summary = DESCRIPTION
29
+ s.description = DESCRIPTION
30
+
31
+ s.extra_rdoc_files = %w()
32
+
33
+ s.authors = ['Robert A. Heiler']
34
+ s.email = 'shevegen@gmail.com'
35
+ s.files = Dir['**/*']
36
+ s.files << 'README.md'
37
+ s.license = 'BSD-2-Clause'
38
+ s.homepage = 'https://github.com/shevegen/ruby_token_parser'
39
+
40
+ s.required_ruby_version = '>= '+RUBY_VERSION
41
+ s.required_rubygems_version = '>= '+Gem::VERSION
42
+ s.rubygems_version = '>= '+Gem::VERSION
43
+
44
+ # ========================================================================= #
45
+ # External dependencies for the project:
46
+ # ========================================================================= #
47
+ # s.add_dependency 'foo'
48
+
49
+ }
@@ -0,0 +1,73 @@
1
+ #!/System/Index/bin/ruby -w
2
+ # Encoding: ISO-8859-1
3
+ # =========================================================================== #
4
+ require 'pp'
5
+ require 'cliner'
6
+ require 'colour_e/autoinclude'
7
+ require 'ruby_token_parser'
8
+
9
+ cliner {
10
+ e 'We will next test the '+simp('RubyTokenParser')
11
+ }
12
+ # =========================================================================== #
13
+ # === test_this_string
14
+ # =========================================================================== #
15
+ def test_this_string(i, optional_argument = nil)
16
+ e 'We will test this input next: '+simp(i)
17
+ x = RubyTokenParser.parse(i, optional_argument)
18
+ pp x
19
+ end
20
+
21
+ _ = '(1..3)'
22
+ test_this_string(_)
23
+ cliner
24
+
25
+ _ = "[1,2,3]"
26
+ test_this_string(_)
27
+ cliner
28
+
29
+ _ = '(1..5)'
30
+ test_this_string(_) # => (1..5)
31
+ cliner
32
+
33
+ _ = 'nil'
34
+ test_this_string(_) # => nil
35
+ cliner
36
+
37
+ # =========================================================================== #
38
+ # === Handle Symbols
39
+ # =========================================================================== #
40
+ _ = ':foo'
41
+ test_this_string(_) # => :foo
42
+ cliner
43
+
44
+ # =========================================================================== #
45
+ # === Handle Integers
46
+ # =========================================================================== #
47
+ _ = '123'
48
+ test_this_string(_) # => 123
49
+ cliner
50
+
51
+ _ = '1.5'
52
+ test_this_string(_) # => 1.5
53
+ cliner
54
+
55
+ _ = '1.5'
56
+ test_this_string(_, use_big_decimal: true) # <BigDecimal:…,'0.15E1',18(18)>
57
+ cliner
58
+
59
+ _ = '[1, 2, 3]'
60
+ test_this_string(_) # => [1, 2, 3]
61
+ cliner
62
+
63
+ _ = '{:a => 1, :b => 2}'
64
+ test_this_string(_) # => {:a => 1, :b => 2}
65
+ cliner
66
+
67
+ _ = '(1..3)'
68
+ test_this_string(_) # => (1..3)
69
+ cliner
70
+
71
+ _ = '"xyz"'
72
+ test_this_string(_) # =>
73
+ cliner
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_token_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Robert A. Heiler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-10-28 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: "\n This project is called ruby_token_parser.\n \n It allows
14
+ one to parse for ruby literals, which can\n be used to return a proper ruby object.\n
15
+ \ \n This project is based on apeiros' prior work, his gem\n is called literal_parser
16
+ - check it out.\n\n If you have specific suggestions to make this gem more\n
17
+ \ useful for others, please drop me an email at:\n\n shevegen@gmail.com\n\n
18
+ \ Thank you.\n"
19
+ email: shevegen@gmail.com
20
+ executables: []
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - LICENSE.txt
25
+ - README.md
26
+ - lib/ruby_token_parser.rb
27
+ - lib/ruby_token_parser/parse.rb
28
+ - lib/ruby_token_parser/requires.rb
29
+ - lib/ruby_token_parser/ruby_token_constants.rb
30
+ - lib/ruby_token_parser/ruby_token_parser.rb
31
+ - ruby_token_parser.gemspec
32
+ - test/testing_ruby_token_parser.rb
33
+ homepage: https://github.com/shevegen/ruby_token_parser
34
+ licenses:
35
+ - BSD-2-Clause
36
+ metadata: {}
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 2.5.3
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.7.7
51
+ requirements: []
52
+ rubyforge_project:
53
+ rubygems_version: 2.7.7
54
+ signing_key:
55
+ specification_version: 4
56
+ summary: 'This project is called ruby_token_parser. It allows one to parse for ruby
57
+ literals, which can be used to return a proper ruby object. This project is based
58
+ on apeiros'' prior work, his gem is called literal_parser - check it out. If you
59
+ have specific suggestions to make this gem more useful for others, please drop me
60
+ an email at: shevegen@gmail.com Thank you.'
61
+ test_files: []