textpow1x 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg/
3
+ *.gemspec
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem 'oniguruma', :platform => :ruby_18
5
+
6
+ group :dev do
7
+ gem 'rake', '0.8.7'
8
+ gem 'jeweler'
9
+ gem 'hoe'
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ textpow1x (0.11.0)
5
+ plist (>= 3.0.1)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ git (1.2.5)
11
+ hoe (2.12.3)
12
+ rake (~> 0.8)
13
+ jeweler (1.6.4)
14
+ bundler (~> 1.0)
15
+ git (>= 1.2.5)
16
+ rake
17
+ oniguruma (1.1.0)
18
+ plist (3.1.0)
19
+ rake (0.8.7)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ hoe
26
+ jeweler
27
+ oniguruma
28
+ rake (= 0.8.7)
29
+ textpow1x!
data/History.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ == 0.11.0 / 2009-06-12
2
+ * Updated to 1.9 compatibility. Does not use onigumura gem anymore
3
+
4
+ == 0.10.1 / 2008-02-20
5
+ * FIX: Endless loop in method_missing when @proxy_variable is not present.
6
+
7
+ == 0.10.0 / 2007-06-15
8
+ * CHANGE: Now the scopeName for the entire syntax is passed to start_parsing and end_parsing. This means that programs using older version should modify their processors accordingly.
9
+
10
+ == 0.9.1 / 2007-06-14
11
+ * FIX: Score manager now handles multiple subtractions in scope definitions.
12
+
13
+ == 0.9.0 / 2007-03-19
14
+
15
+ * 1 major enhancement
16
+ * Birthday!
17
+
data/Manifest.txt ADDED
@@ -0,0 +1,13 @@
1
+ bin/plist2yaml
2
+ bin/plist2syntax
3
+ lib/textpow.rb
4
+ lib/textpow
5
+ lib/textpow/syntax.rb
6
+ lib/textpow/version.rb
7
+ lib/textpow/score_manager.rb
8
+ lib/textpow/debug_processor.rb
9
+ test/test_textpow.rb
10
+ History.rdoc
11
+ Rakefile
12
+ Manifest.txt
13
+ README.rdoc
data/README.rdoc ADDED
@@ -0,0 +1,212 @@
1
+ A library for parsing {TextMate}[http://macromates.com/] bundles.
2
+
3
+ For Ruby 1.8 and 1.9.
4
+
5
+
6
+ == INSTALL:
7
+
8
+ gem install textpow1x
9
+
10
+ === Ruby 1.8
11
+ Install oniguruma
12
+
13
+ # Ubuntu
14
+ sudo apt-get -y install libonig-dev
15
+ gem install oniguruma
16
+
17
+ # OsX (no idea if this works...)
18
+ port install oniguruma4
19
+
20
+
21
+ == USAGE:
22
+
23
+ 1. Get a .tmSyntax File
24
+
25
+ 2. Load the Syntax File:
26
+
27
+ require 'textpow'
28
+ syntax = Textpow::SyntaxNode.load("ruby.tmSyntax")
29
+
30
+ 3. Initialize a processor:
31
+
32
+ processor = Textpow::DebugProcessor.new
33
+
34
+ 4. Parse some text:
35
+
36
+ syntax.parse( text, processor )
37
+
38
+
39
+ === INDEPTH:
40
+
41
+ At the heart of syntax parsing are ..., well, syntax files. Lets see for instance
42
+ the example syntax that appears in textmate's
43
+ {documentation}[http://macromates.com/textmate/manual/language_grammars#language_grammars]:
44
+
45
+
46
+ { scopeName = 'source.untitled';
47
+ fileTypes = ( txt );
48
+ foldingStartMarker = '\{\s*$';
49
+ foldingStopMarker = '^\s*\}';
50
+ patterns = (
51
+ { name = 'keyword.control.untitled';
52
+ match = '\b(if|while|for|return)\b';
53
+ },
54
+ { name = 'string.quoted.double.untitled';
55
+ begin = '"';
56
+ end = '"';
57
+ patterns = (
58
+ { name = 'constant.character.escape.untitled';
59
+ match = '\\.';
60
+ }
61
+ );
62
+ },
63
+ );
64
+ }
65
+
66
+ But Textpow is not able to parse text pfiles. However, in practice this is not a problem,
67
+ since it is possible to convert both text and binary pfiles to an XML format. Indeed, all
68
+ the syntaxes in the Textmate syntax {repository}[http://macromates.com/svn/Bundles/trunk/Bundles/]
69
+ are in XML format:
70
+
71
+ <?xml version="1.0" encoding="UTF-8"?>
72
+ <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
73
+ <plist version="1.0">
74
+ <dict>
75
+ <key>scopeName</key>
76
+ <string>source.untitled</string>
77
+ <key>fileTypes</key>
78
+ <array>
79
+ <string>txt</string>
80
+ </array>
81
+ <key>foldingStartMarker</key>
82
+ <string>\{\s*$</string>
83
+ <key>foldingStopMarker</key>
84
+ <string>^\s*\}</string>
85
+ <key>patterns</key>
86
+ <array>
87
+ <dict>
88
+ <key>name</key>
89
+ <string>keyword.control.untitled</string>
90
+ <key>match</key>
91
+ <string>\b(if|while|for|return)\b</string>
92
+ </dict>
93
+ <dict>
94
+ <key>name</key>
95
+ <string>string.quoted.double.untitled</string>
96
+ <key>begin</key>
97
+ <string>"</string>
98
+ <key>end</key>
99
+ <string>"</string>
100
+ <key>patterns</key>
101
+ <array>
102
+ <dict>
103
+ <key>name</key>
104
+ <string>constant.character.escape.untitled</string>
105
+ <key>match</key>
106
+ <string>\\.</string>
107
+ </dict>
108
+ </array>
109
+ </dict>
110
+ </array>
111
+ </dict>
112
+
113
+ Of course, most people find XML both ugly and cumbersome. Fortunately, it is
114
+ also possible to store syntax files in YAML format, which is much easier to
115
+ read:
116
+
117
+ ---
118
+ fileTypes:
119
+ - txt
120
+ scopeName: source.untitled
121
+ foldingStartMarker: \{\s*$
122
+ foldingStopMarker: ^\s*\}
123
+ patterns:
124
+ - name: keyword.control.untitled
125
+ match: \b(if|while|for|return)\b
126
+ - name: string.quoted.double.untitled
127
+ begin: '"'
128
+ end: '"'
129
+ patterns:
130
+ - name: constant.character.escape.untitled
131
+ match: \\.
132
+
133
+ ==== Processors
134
+
135
+ Until now we have talked about the parsing process without explaining what
136
+ it is exactly. Basically, parsing consists in reading text from a string or
137
+ file and applying tags to parts of the text according to what has been
138
+ specified in the syntax file.
139
+
140
+ In textpow, the process takes place line by line, from the beginning to the
141
+ end and from left to right for every line. As the text is parsed, events are
142
+ sent to a processor object when a tag is open or closed and so on.
143
+ A processor is any object which implements one or more of the following
144
+ methods:
145
+
146
+ class Processor
147
+ def open_tag name, position
148
+ end
149
+
150
+ def close_tag name, position
151
+ end
152
+
153
+ def new_line line
154
+ end
155
+
156
+ def start_parsing name
157
+ end
158
+
159
+ def end_parsing name
160
+ end
161
+ end
162
+
163
+ * <tt>open_tag</tt>. Is called when a new tag is opened, it receives the tag's name and
164
+ its position (relative to the current line).
165
+ * <tt>close_tag</tt>. The same that <tt>open_tag</tt>, but it is called when a tag is closed.
166
+ * <tt>new_line</tt>. Is called every time that a new line is processed, it receives the
167
+ line's contents.
168
+ * <tt>start_parsing</tt>. Is called once at the beginning of the parsing process. It
169
+ receives the scope name for the syntax being used.
170
+ * <tt>end_parsing</tt>. Is called once after all the input text has been parsed. It
171
+ receives the scope name for the syntax being used.
172
+
173
+ Textpow ensures that the methods are called in parsing order, thus,
174
+ for example, if there are two subsequent calls to <tt>open_tag</tt>, the first
175
+ having <tt>name="text.string", position=10</tt> and the second having
176
+ <tt>name="markup.string", position=10</tt>, it should be understood that the
177
+ <tt>"markup.string"</tt> tag is inside the <tt>"text.string"</tt> tag.
178
+
179
+ == CREDITS:
180
+
181
+ * {Michael Grosser}[http://github.com/grosser]
182
+ * {Chris Hoffman}[http://github.com/cehoffman]
183
+ * {Spox}[http://github.com/spox]
184
+ * Dizan Vasque
185
+
186
+ == LICENSE:
187
+
188
+ (The MIT License)
189
+
190
+ * Copyright (c) 2011 Michael Grosser
191
+ * Copyright (c) 2010 Chris Hoffman
192
+ * Copyright (c) 2009 Spox
193
+ * Copyright (c) 2007-2008 Dizan Vasquez
194
+
195
+ Permission is hereby granted, free of charge, to any person obtaining
196
+ a copy of this software and associated documentation files (the
197
+ 'Software'), to deal in the Software without restriction, including
198
+ without limitation the rights to use, copy, modify, merge, publish,
199
+ distribute, sublicense, and/or sell copies of the Software, and to
200
+ permit persons to whom the Software is furnished to do so, subject to
201
+ the following conditions:
202
+
203
+ The above copyright notice and this permission notice shall be
204
+ included in all copies or substantial portions of the Software.
205
+
206
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
207
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
208
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
209
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
210
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
211
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
212
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new do |test|
6
+ test.libs << 'lib'
7
+ test.pattern = 'test/**/*_test.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
data/bin/plist2syntax ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'plist'
5
+ require 'yaml'
6
+
7
+ result = Plist::parse_xml( ARGV[0] )
8
+ standard_name = File.basename( ARGV[0] ).downcase.gsub(/\s+/, '_').gsub(/\.(plist|tm[Ll]anguage)/, '').gsub(/\(|\)|:/, '').gsub(/_+/, '_')
9
+ puts standard_name
10
+
11
+ File.open( "#{standard_name}.yaml", "w" ) {|f| YAML.dump( result, f ) }
data/bin/plist2yaml ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'plist'
5
+ require 'yaml'
6
+
7
+ result = Plist::parse_xml( ARGV[0] )
8
+ YAML.dump( result, STDOUT )
@@ -0,0 +1,36 @@
1
+ module Textpow
2
+ class DebugProcessor
3
+ def initialize
4
+ @line_number = 0
5
+ @printable_line = ""
6
+ end
7
+
8
+ def pprint line, string, position = 0
9
+ line.replace line.ljust( position + string.size, " ")
10
+ line[position,string.size] = string
11
+ line
12
+ end
13
+
14
+ def open_tag name, position
15
+ STDERR.puts pprint( "", "{#{name}", position + @line_marks.size)
16
+ end
17
+
18
+ def close_tag name, position
19
+ STDERR.puts pprint( "", "}#{name}", position + @line_marks.size)
20
+ end
21
+
22
+ def new_line line
23
+ @line_number += 1
24
+ @line_marks = "[#{@line_number.to_s.rjust( 4, '0' )}] "
25
+ STDERR.puts "#{@line_marks}#{line}"
26
+ end
27
+
28
+ def start_parsing name
29
+ STDERR.puts "{#{name}"
30
+ end
31
+
32
+ def end_parsing name
33
+ STDERR.puts "}#{name}"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,65 @@
1
+ module Textpow
2
+ class ScoreManager
3
+ POINT_DEPTH = 4
4
+ NESTING_DEPTH = 40
5
+ START_VALUE = 2 ** ( POINT_DEPTH * NESTING_DEPTH )
6
+ BASE = 2 ** POINT_DEPTH
7
+
8
+ def initialize
9
+ @scores = {}
10
+ end
11
+
12
+ def score search_scope, reference_scope
13
+ max = 0
14
+ search_scope.split( ',' ).each do |scope|
15
+ arrays = scope.split(/\B-/)
16
+ if arrays.size == 1
17
+ max = [max, score_term( arrays[0], reference_scope )].max
18
+ elsif arrays.size > 1
19
+ excluded = false
20
+ arrays[1..-1].each do |a|
21
+ if score_term( arrays[1], reference_scope ) > 0
22
+ excluded = true
23
+ break
24
+ end
25
+ end
26
+ max = [max, score_term( arrays[0], reference_scope )].max unless excluded
27
+ else
28
+ raise ParsingError, "Error in scope string: '#{search_scope}' #{arrays.size} is not a valid number of operands" if arrays.size < 1
29
+ end
30
+ end
31
+ max
32
+ end
33
+
34
+ private
35
+
36
+ def score_term search_scope, reference_scope
37
+ unless @scores[reference_scope] && @scores[reference_scope][search_scope]
38
+ @scores[reference_scope] ||= {}
39
+ @scores[reference_scope][search_scope] = score_array( search_scope.split(' '), reference_scope.split( ' ' ) )
40
+ end
41
+ @scores[reference_scope][search_scope]
42
+ end
43
+
44
+ def score_array search_array, reference_array
45
+ pending = search_array
46
+ current = reference_array.last
47
+ reg = Regexp.new( "^#{Regexp.escape( pending.last )}" )
48
+ multiplier = START_VALUE
49
+ result = 0
50
+ while pending.size > 0 && current
51
+ if reg =~ current
52
+ point_score = (2**POINT_DEPTH) - current.count( '.' ) + Regexp.last_match[0].count( '.' )
53
+ result += point_score * multiplier
54
+ pending.pop
55
+ reg = Regexp.new( "^#{Regexp.escape( pending.last )}" ) if pending.size > 0
56
+ end
57
+ multiplier = multiplier / BASE
58
+ reference_array.pop
59
+ current = reference_array.last
60
+ end
61
+ result = 0 if pending.size > 0
62
+ result
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,323 @@
1
+ module Textpow
2
+ RUBY_19 = (RUBY_VERSION > "1.9.0")
3
+ end
4
+ require 'oniguruma' unless Textpow::RUBY_19
5
+
6
+ require 'plist'
7
+
8
+ module Textpow
9
+ class SyntaxProxy
10
+ def initialize hash, syntax
11
+ @syntax = syntax
12
+ @proxy = hash["include"]
13
+ end
14
+
15
+ def method_missing method, *args, &block
16
+ if @proxy
17
+ @proxy_value = proxy unless @proxy_value
18
+ if @proxy_value
19
+ @proxy_value.send(method, *args, &block)
20
+ else
21
+ STDERR.puts "Failed proxying #{@proxy}.#{method}(#{args.join(', ')})"
22
+ end
23
+ end
24
+ end
25
+
26
+ def proxy
27
+ case @proxy
28
+ when /^#/
29
+ if @syntax.repository && @syntax.repository[@proxy[1..-1]]
30
+ #puts "Repository"
31
+ #@table["syntax"].repository.each_key{|k| puts k}
32
+ return @syntax.repository[@proxy[1..-1]]
33
+ end
34
+ when "$self"
35
+ return @syntax
36
+ when "$base"
37
+ return @syntax
38
+ else
39
+ return @syntax.syntaxes[@proxy]
40
+ end
41
+ end
42
+ end
43
+
44
+ class SyntaxNode
45
+ unless Textpow::RUBY_19
46
+ OPTIONS = {:options => Oniguruma::OPTION_CAPTURE_GROUP}
47
+ end
48
+
49
+ @@syntaxes = {}
50
+
51
+ attr_accessor :syntax
52
+ attr_accessor :firstLineMatch
53
+ attr_accessor :foldingStartMarker
54
+ attr_accessor :foldingStopMarker
55
+ attr_accessor :match
56
+ attr_accessor :begin
57
+ attr_accessor :content
58
+ attr_accessor :fileTypes
59
+ attr_accessor :name
60
+ attr_accessor :contentName
61
+ attr_accessor :end
62
+ attr_accessor :scopeName
63
+ attr_accessor :keyEquivalent
64
+ attr_accessor :captures
65
+ attr_accessor :beginCaptures
66
+ attr_accessor :endCaptures
67
+ attr_accessor :repository
68
+ attr_accessor :patterns
69
+
70
+ def self.load filename, name_space = :default
71
+ table = nil
72
+ case filename
73
+ when /(\.tmSyntax|\.plist)$/
74
+ table = Plist::parse_xml( filename )
75
+ else
76
+ File.open( filename ) do |f|
77
+ table = YAML.load( f )
78
+ end
79
+ end
80
+ if table
81
+ SyntaxNode.new( table, nil, name_space )
82
+ else
83
+ nil
84
+ end
85
+ end
86
+
87
+ def initialize hash, syntax = nil, name_space = :default
88
+ @name_space = name_space
89
+ @@syntaxes[@name_space] ||= {}
90
+ @@syntaxes[@name_space][hash["scopeName"]] = self if hash["scopeName"]
91
+ @syntax = syntax || self
92
+ hash.each do |key, value|
93
+ case key
94
+ when "firstLineMatch", "foldingStartMarker", "foldingStopMarker", "match", "begin"
95
+ begin
96
+ if Textpow::RUBY_19
97
+ value.force_encoding("ASCII-8BIT")
98
+ instance_variable_set( "@#{key}", Regexp.new( value ) )
99
+ else
100
+ instance_variable_set( "@#{key}", Oniguruma::ORegexp.new( value, OPTIONS ) )
101
+ end
102
+ rescue ArgumentError => e
103
+ raise ParsingError, "Parsing error in #{value}: #{e.to_s}"
104
+ end
105
+ when "content", "fileTypes", "name", "contentName", "end", "scopeName", "keyEquivalent"
106
+ instance_variable_set( "@#{key}", value )
107
+ when "captures", "beginCaptures", "endCaptures"
108
+ instance_variable_set( "@#{key}", value.sort )
109
+ when "repository"
110
+ parse_repository value
111
+ when "patterns"
112
+ create_children value
113
+ else
114
+ STDERR.puts "Ignoring: #{key} => #{value.gsub("\n", "\n>>")}" if $DEBUG
115
+ end
116
+ end
117
+ end
118
+
119
+
120
+ def syntaxes
121
+ @@syntaxes[@name_space]
122
+ end
123
+
124
+ def parse( string, processor = nil )
125
+ processor.start_parsing self.scopeName if processor
126
+ stack = [[self, nil]]
127
+ string.each_line do |line|
128
+ parse_line stack, line, processor
129
+ end
130
+ processor.end_parsing self.scopeName if processor
131
+ processor
132
+ end
133
+
134
+ protected
135
+
136
+ def parse_repository repository
137
+ @repository = {}
138
+ repository.each do |key, value|
139
+ if value["include"]
140
+ @repository[key] = SyntaxProxy.new( value, self.syntax )
141
+ else
142
+ @repository[key] = SyntaxNode.new( value, self.syntax, @name_space )
143
+ end
144
+ end
145
+ end
146
+
147
+ def create_children patterns
148
+ @patterns = []
149
+ patterns.each do |p|
150
+ if p["include"]
151
+ @patterns << SyntaxProxy.new( p, self.syntax )
152
+ else
153
+ @patterns << SyntaxNode.new( p, self.syntax, @name_space )
154
+ end
155
+ end
156
+ end
157
+
158
+ def parse_captures name, pattern, match, processor
159
+ captures = pattern.match_captures( name, match )
160
+ captures.reject! { |group, range, name| ! range.first || range.first == range.last }
161
+ starts = []
162
+ ends = []
163
+ captures.each do |group, range, name|
164
+ starts << [range.first, group, name]
165
+ ends << [range.last, -group, name]
166
+ end
167
+
168
+ # STDERR.puts '-' * 100
169
+ # starts.sort!.reverse!.each{|c| STDERR.puts c.join(', ')}
170
+ # STDERR.puts
171
+ # ends.sort!.reverse!.each{|c| STDERR.puts c.join(', ')}
172
+ starts.sort!.reverse!
173
+ ends.sort!.reverse!
174
+
175
+ while ! starts.empty? || ! ends.empty?
176
+ if starts.empty?
177
+ pos, key, name = ends.pop
178
+ processor.close_tag name, pos
179
+ elsif ends.empty?
180
+ pos, key, name = starts.pop
181
+ processor.open_tag name, pos
182
+ elsif ends.last[1].abs < starts.last[1]
183
+ pos, key, name = ends.pop
184
+ processor.close_tag name, pos
185
+ else
186
+ pos, key, name = starts.pop
187
+ processor.open_tag name, pos
188
+ end
189
+ end
190
+ end
191
+
192
+ def match_captures name, match
193
+ matches = []
194
+ captures = instance_variable_get "@#{name}"
195
+ if captures
196
+ captures.each do |key, value|
197
+ if key =~ /^\d*$/
198
+ matches << [key.to_i, match.offset( key.to_i ), value["name"]] if key.to_i < match.size
199
+ else
200
+ matches << [match.to_index( key.to_sym ), match.offset( key.to_sym), value["name"]] if match.to_index( key.to_sym )
201
+ end
202
+ end
203
+ end
204
+ matches
205
+ end
206
+
207
+ def match_first string, position
208
+ if self.match
209
+ if match = self.match.match( string, position )
210
+ return [self, match]
211
+ end
212
+ elsif self.begin
213
+ if match = self.begin.match( string, position )
214
+ return [self, match]
215
+ end
216
+ elsif self.end
217
+ else
218
+ return match_first_son( string, position )
219
+ end
220
+ nil
221
+ end
222
+
223
+ def match_end string, match, position
224
+ regstring = self.end.clone
225
+ regstring.gsub!( /\\([1-9])/ ) { |s| match[$1.to_i] }
226
+
227
+ # in spox-textpow this is \\g in 1.9 !?
228
+ regstring.gsub!( /\\k<(.*?)>/ ) { |s| match[$1.to_sym] }
229
+ if Textpow::RUBY_19
230
+ Regexp.new( regstring ).match( string, position )
231
+ else
232
+ Oniguruma::ORegexp.new( regstring ).match( string, position )
233
+ end
234
+ end
235
+
236
+ def match_first_son string, position
237
+ match = nil
238
+ if self.patterns
239
+ self.patterns.each do |p|
240
+ tmatch = p.match_first string, position
241
+ if tmatch
242
+ ok = if Textpow::RUBY_19
243
+ ! match || match[1].offset(0).first > tmatch[1].offset(0).first
244
+ else
245
+ ! match || match[1].offset.first > tmatch[1].offset.first
246
+ end
247
+ match = tmatch if ok
248
+ #break if tmatch[1].offset.first == position
249
+ end
250
+ end
251
+ end
252
+ match
253
+ end
254
+
255
+ def parse_line stack, line, processor
256
+ processor.new_line line if processor
257
+ top, match = stack.last
258
+ position = 0
259
+ #@ln ||= 0
260
+ #@ln += 1
261
+ #STDERR.puts @ln
262
+ while true
263
+ if top.patterns
264
+ pattern, pattern_match = top.match_first_son line, position
265
+ else
266
+ pattern, pattern_match = nil
267
+ end
268
+
269
+ end_match = nil
270
+ if top.end
271
+ end_match = top.match_end( line, match, position )
272
+ end
273
+
274
+ ok = if Textpow::RUBY_19
275
+ end_match && ( ! pattern_match || pattern_match.offset(0).first >= end_match.offset(0).first )
276
+ else
277
+ end_match && ( ! pattern_match || pattern_match.offset.first >= end_match.offset.first )
278
+ end
279
+
280
+ if ok
281
+ pattern_match = end_match
282
+ if Textpow::RUBY_19
283
+ start_pos = pattern_match.offset(0).first
284
+ end_pos = pattern_match.offset(0).last
285
+ else
286
+ start_pos = pattern_match.offset.first
287
+ end_pos = pattern_match.offset.last
288
+ end
289
+ processor.close_tag top.contentName, start_pos if top.contentName && processor
290
+ parse_captures "captures", top, pattern_match, processor if processor
291
+ parse_captures "endCaptures", top, pattern_match, processor if processor
292
+ processor.close_tag top.name, end_pos if top.name && processor
293
+ stack.pop
294
+ top, match = stack.last
295
+ else
296
+ break unless pattern
297
+ if Textpow::RUBY_19
298
+ start_pos = pattern_match.offset(0).first
299
+ end_pos = pattern_match.offset(0).last
300
+ else
301
+ start_pos = pattern_match.offset.first
302
+ end_pos = pattern_match.offset.last
303
+ end
304
+
305
+ if pattern.begin
306
+ processor.open_tag pattern.name, start_pos if pattern.name && processor
307
+ parse_captures "captures", pattern, pattern_match, processor if processor
308
+ parse_captures "beginCaptures", pattern, pattern_match, processor if processor
309
+ processor.open_tag pattern.contentName, end_pos if pattern.contentName && processor
310
+ top = pattern
311
+ match = pattern_match
312
+ stack << [top, match]
313
+ elsif pattern.match
314
+ processor.open_tag pattern.name, start_pos if pattern.name && processor
315
+ parse_captures "captures", pattern, pattern_match, processor if processor
316
+ processor.close_tag pattern.name, end_pos if pattern.name && processor
317
+ end
318
+ end
319
+ position = end_pos
320
+ end
321
+ end
322
+ end
323
+ end
@@ -0,0 +1,3 @@
1
+ module Textpow
2
+ Version = "0.11.0"
3
+ end
data/lib/textpow.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'yaml'
2
+ require 'textpow/syntax'
3
+ require 'textpow/debug_processor'
4
+ require 'textpow/score_manager'
5
+ require 'textpow/version'
6
+
7
+ module Textpow
8
+ class ParsingError < Exception; end
9
+ end
10
+
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'textpow'
3
+ require 'test/unit'
4
+
5
+ class ScoreManagerTest < Test::Unit::TestCase
6
+ include Textpow
7
+
8
+ def test_score
9
+ sp = ScoreManager.new
10
+ reference_scope = 'text.html.basic source.php.embedded.html string.quoted.double.php'
11
+
12
+ assert_not_equal( 0, sp.score( 'source.php string', reference_scope ) )
13
+ assert_not_equal( 0, sp.score( 'text.html source.php', reference_scope ) )
14
+ assert_equal( 0, sp.score( 'string source.php', reference_scope ) )
15
+ assert_equal( 0, sp.score( 'source.php text.html', reference_scope ) )
16
+
17
+ assert_equal( 0, sp.score( 'text.html source.php - string', reference_scope ) )
18
+ assert_not_equal( 0, sp.score( 'text.html source.php - ruby', reference_scope ) )
19
+
20
+ assert( sp.score( 'string', reference_scope ) > sp.score( 'source.php', reference_scope ) )
21
+ assert( sp.score( 'string.quoted', reference_scope ) > sp.score( 'source.php', reference_scope ) )
22
+ assert( sp.score( 'text source string', reference_scope ) > sp.score( 'source string', reference_scope ) )
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: textpow1x
3
+ version: !ruby/object:Gem::Version
4
+ hash: 51
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 11
9
+ - 0
10
+ version: 0.11.0
11
+ platform: ruby
12
+ authors:
13
+ - Dizan Vasquez
14
+ - Spox
15
+ - Chris Hoffman
16
+ - Michael Grosser
17
+ autorequire:
18
+ bindir: bin
19
+ cert_chain: []
20
+
21
+ date: 2011-09-12 00:00:00 +02:00
22
+ default_executable:
23
+ dependencies:
24
+ - !ruby/object:Gem::Dependency
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 5
31
+ segments:
32
+ - 3
33
+ - 0
34
+ - 1
35
+ version: 3.0.1
36
+ type: :runtime
37
+ name: plist
38
+ version_requirements: *id001
39
+ prerelease: false
40
+ description: A library for parsing TextMate bundles on ruby 1.x
41
+ email:
42
+ - michael@grosser.it
43
+ executables:
44
+ - plist2yaml
45
+ - plist2syntax
46
+ extensions: []
47
+
48
+ extra_rdoc_files: []
49
+
50
+ files:
51
+ - .gitignore
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - History.rdoc
55
+ - Manifest.txt
56
+ - README.rdoc
57
+ - Rakefile
58
+ - bin/plist2syntax
59
+ - bin/plist2yaml
60
+ - lib/textpow.rb
61
+ - lib/textpow/debug_processor.rb
62
+ - lib/textpow/score_manager.rb
63
+ - lib/textpow/syntax.rb
64
+ - lib/textpow/version.rb
65
+ - test/textpow_test.rb
66
+ has_rdoc: true
67
+ homepage: http://github.com/grosser/textpow
68
+ licenses:
69
+ - MIT
70
+ post_install_message:
71
+ rdoc_options:
72
+ - --main
73
+ - README.rdoc
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.6.2
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: A library for parsing TextMate bundles on ruby 1.x
101
+ test_files: []
102
+