tickly 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +3 -1
- data/Gemfile +1 -1
- data/lib/tickly/parser.rb +48 -89
- data/lib/tickly.rb +1 -1
- data/tickly.gemspec +4 -4
- metadata +4 -4
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/lib/tickly/parser.rb
CHANGED
@@ -4,22 +4,6 @@ require 'bychar'
|
|
4
4
|
module Tickly
|
5
5
|
|
6
6
|
|
7
|
-
# Since you parse char by char, you will likely call
|
8
|
-
# eof? on each iteration. Instead. allow it to raise and do not check.
|
9
|
-
# This takes the profile time down from 36 seconds to 30 seconds
|
10
|
-
# for a large file.
|
11
|
-
class EOFError < RuntimeError #:nodoc: all
|
12
|
-
end
|
13
|
-
|
14
|
-
class W < Bychar::Reader #:nodoc: all
|
15
|
-
def read_one_byte
|
16
|
-
cache if @buf.eos?
|
17
|
-
raise EOFError if @buf.eos?
|
18
|
-
|
19
|
-
@buf.getch
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
7
|
# Simplistic, incomplete and most likely incorrect TCL parser
|
24
8
|
class Parser
|
25
9
|
|
@@ -30,7 +14,7 @@ module Tickly
|
|
30
14
|
def parse(io_or_str)
|
31
15
|
bare_io = io_or_str.respond_to?(:read) ? io_or_str : StringIO.new(io_or_str)
|
32
16
|
# Wrap the IO in a Bychar buffer to read faster
|
33
|
-
reader =
|
17
|
+
reader = Bychar::Reader.new(bare_io)
|
34
18
|
sub_parse(reader)
|
35
19
|
end
|
36
20
|
|
@@ -45,112 +29,87 @@ module Tickly
|
|
45
29
|
TERMINATORS = ["\n", ";"]
|
46
30
|
ESC = 92.chr # Backslash (\)
|
47
31
|
|
32
|
+
# Package the expressions, stack and buffer.
|
33
|
+
# We use a special flag to tell us whether we need multuple expressions
|
34
|
+
# or not, if not we just discard them
|
35
|
+
def wrap_up(expressions, stack, buf, stack_depth, multiple_expressions)
|
36
|
+
stack << buf if (buf.length > 0)
|
37
|
+
return stack unless multiple_expressions
|
38
|
+
|
39
|
+
expressions << stack if stack.any?
|
40
|
+
expressions.each { |expr| expand_subexpr!(expr, stack_depth + 1) }
|
41
|
+
|
42
|
+
return expressions
|
43
|
+
end
|
44
|
+
|
48
45
|
# Parse from a passed IO object either until an unescaped stop_char is reached
|
49
46
|
# or until the IO is exhausted. The last argument is the class used to
|
50
47
|
# compose the subexpression being parsed. The subparser is reentrant and not
|
51
48
|
# destructive for the object containing it.
|
52
49
|
def sub_parse(io, stop_char = nil, stack_depth = 0)
|
53
50
|
# A standard stack is an expression that does not evaluate to a string
|
51
|
+
expressions = []
|
54
52
|
stack = []
|
55
53
|
buf = ''
|
56
54
|
last_char_was_linebreak = false
|
55
|
+
multiple_expressions = false
|
57
56
|
|
58
57
|
no_eof do
|
59
|
-
char = io.read_one_byte
|
60
|
-
|
61
|
-
if
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
78
|
-
elsif char == '[' # Opens a new string expression
|
79
|
-
stack << buf if (buf.length > 0)
|
80
|
-
last_char_was_linebreak = false
|
81
|
-
stack << [:b] + sub_parse(io, ']', stack_depth + 1)
|
82
|
-
elsif char == '{' # Opens a new literal expression
|
83
|
-
stack << buf if (buf.length > 0)
|
84
|
-
last_char_was_linebreak = false
|
85
|
-
stack << [:c] + sub_parse(io, '}', stack_depth + 1)
|
86
|
-
elsif char == '"'
|
87
|
-
stack << buf if (buf.length > 0)
|
88
|
-
last_char_was_linebreak = false
|
89
|
-
stack << parse_str(io, '"')
|
90
|
-
elsif char == "'"
|
91
|
-
stack << buf if (buf.length > 0)
|
92
|
-
last_char_was_linebreak = false
|
93
|
-
stack << parse_str(io, "'")
|
58
|
+
char = io.read_one_byte!
|
59
|
+
|
60
|
+
if char == stop_char # Bail out of a subexpr
|
61
|
+
# Handle any remaining subexpressions
|
62
|
+
return wrap_up(expressions, stack, buf, stack_depth, multiple_expressions)
|
63
|
+
elsif char == " " || char == "\n" # Space
|
64
|
+
if buf.length > 0
|
65
|
+
stack << buf
|
66
|
+
buf = ''
|
67
|
+
end
|
68
|
+
if TERMINATORS.include?(char) && stack.any? && !last_char_was_linebreak # Introduce a stack separator! This is a new line
|
69
|
+
stack << buf if buf.length > 0
|
70
|
+
expressions << stack
|
71
|
+
stack = []
|
72
|
+
last_char_was_linebreak = true
|
73
|
+
multiple_expressions = true
|
74
|
+
#puts "Next expression! #{expressions.inspect} #{stack.inspect} #{buf.inspect}"
|
94
75
|
else
|
95
76
|
last_char_was_linebreak = false
|
96
|
-
buf << char
|
97
77
|
end
|
78
|
+
elsif char == '[' # Opens a new string expression
|
79
|
+
stack << buf if (buf.length > 0)
|
80
|
+
stack << [:b] + sub_parse(io, ']', stack_depth + 1)
|
81
|
+
elsif char == '{' # Opens a new literal expression
|
82
|
+
stack << buf if (buf.length > 0)
|
83
|
+
stack << [:c] + sub_parse(io, '}', stack_depth + 1)
|
84
|
+
elsif char == '"'
|
85
|
+
stack << buf if (buf.length > 0)
|
86
|
+
stack << parse_str(io, '"')
|
87
|
+
elsif char == "'"
|
88
|
+
stack << buf if (buf.length > 0)
|
89
|
+
stack << parse_str(io, "'")
|
98
90
|
else
|
99
|
-
last_char_was_linebreak = false
|
100
91
|
buf << char
|
101
92
|
end
|
102
93
|
end
|
103
|
-
|
104
|
-
# Ramass any remaining buffer contents
|
105
|
-
stack << buf if (buf.length > 0)
|
106
|
-
|
107
|
-
# Handle any remaining subexpressions
|
108
|
-
if stack.include?(nil)
|
109
|
-
stack = handle_expr_terminator(stack, stack_depth)
|
110
|
-
end
|
111
|
-
# Chip awiy the trailing null
|
112
|
-
chomp!(stack)
|
113
94
|
|
114
|
-
return stack
|
95
|
+
return wrap_up(expressions, stack, buf, stack_depth, multiple_expressions)
|
115
96
|
end
|
116
97
|
|
117
98
|
def chomp!(stack)
|
118
99
|
stack.delete_at(-1) if stack.any? && stack[-1].nil?
|
119
100
|
end
|
120
101
|
|
121
|
-
def handle_expr_terminator(stack, stack_depth)
|
122
|
-
# Figure out whether there was a previous expr terminator
|
123
|
-
previous_i = stack.index(nil)
|
124
|
-
# If there were none, just get this over with. Wrap the stack contents
|
125
|
-
# into a subexpression and carry on.
|
126
|
-
unless previous_i
|
127
|
-
subexpr = stack
|
128
|
-
expand_subexpr!(subexpr, stack_depth + 1)
|
129
|
-
return [subexpr] + [nil]
|
130
|
-
end
|
131
|
-
|
132
|
-
# Now, if there was one, we are the next subexpr in line that just terminated.
|
133
|
-
# What we need to do is pick out all the elements from that terminator onwards
|
134
|
-
# and wrap them.
|
135
|
-
subexpr = stack[previous_i+1..-1]
|
136
|
-
|
137
|
-
# Use expand_subexpr! to trim away any fat that we don't need
|
138
|
-
expand_subexpr!(subexpr, stack_depth + 1)
|
139
|
-
|
140
|
-
return stack[0...previous_i] + [subexpr] + [nil]
|
141
|
-
end
|
142
|
-
|
143
102
|
def no_eof(&blk)
|
144
103
|
begin
|
145
104
|
loop(&blk)
|
146
|
-
rescue EOFError
|
105
|
+
rescue Bychar::EOFError
|
147
106
|
end
|
148
107
|
end
|
149
108
|
|
150
109
|
def parse_str(io, stop_char)
|
151
110
|
buf = ''
|
152
111
|
no_eof do
|
153
|
-
c = io.read_one_byte
|
112
|
+
c = io.read_one_byte!
|
154
113
|
if c == stop_char && buf[LAST_CHAR] != ESC
|
155
114
|
return buf
|
156
115
|
elsif buf[LAST_CHAR] == ESC # Eat out the escape char
|
data/lib/tickly.rb
CHANGED
data/tickly.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "tickly"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Julik Tarkhanov"]
|
@@ -54,14 +54,14 @@ Gem::Specification.new do |s|
|
|
54
54
|
s.specification_version = 3
|
55
55
|
|
56
56
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
57
|
-
s.add_runtime_dependency(%q<bychar>, ["~> 1.
|
57
|
+
s.add_runtime_dependency(%q<bychar>, ["~> 1.1"])
|
58
58
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
59
59
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
60
60
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
61
61
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
62
62
|
s.add_development_dependency(%q<ruby-prof>, [">= 0"])
|
63
63
|
else
|
64
|
-
s.add_dependency(%q<bychar>, ["~> 1.
|
64
|
+
s.add_dependency(%q<bychar>, ["~> 1.1"])
|
65
65
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
66
66
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
67
67
|
s.add_dependency(%q<bundler>, [">= 0"])
|
@@ -69,7 +69,7 @@ Gem::Specification.new do |s|
|
|
69
69
|
s.add_dependency(%q<ruby-prof>, [">= 0"])
|
70
70
|
end
|
71
71
|
else
|
72
|
-
s.add_dependency(%q<bychar>, ["~> 1.
|
72
|
+
s.add_dependency(%q<bychar>, ["~> 1.1"])
|
73
73
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
74
74
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
75
75
|
s.add_dependency(%q<bundler>, [">= 0"])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tickly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
21
|
+
version: '1.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.
|
29
|
+
version: '1.1'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: shoulda
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,7 +156,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
156
|
version: '0'
|
157
157
|
segments:
|
158
158
|
- 0
|
159
|
-
hash:
|
159
|
+
hash: 1707085798664396026
|
160
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
161
|
none: false
|
162
162
|
requirements:
|