ruby_token_parser 0.0.6

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.
@@ -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: []