ripper-tags 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +3 -0
- data/Gemfile +1 -1
- data/LICENSE +21 -0
- data/README.md +15 -45
- data/bin/ripper-tags +8 -93
- data/lib/ripper-tags/data_reader.rb +125 -0
- data/lib/ripper-tags/default_formatter.rb +67 -0
- data/lib/ripper-tags/emacs_formatter.rb +69 -0
- data/lib/ripper-tags/json_formatter.rb +10 -0
- data/lib/{tag_ripper.rb → ripper-tags/parser.rb} +141 -13
- data/lib/ripper-tags/vim_formatter.rb +74 -0
- data/lib/ripper-tags.rb +120 -0
- data/ripper-tags.gemspec +3 -1
- data/test/fixtures/_git/hooks/hook.rb +0 -0
- data/test/fixtures/encoding.rb +4 -0
- data/test/fixtures/non-script.txt +0 -0
- data/test/fixtures/very/deep/script.rb +0 -0
- data/test/fixtures/very/inter.rb +0 -0
- data/test/test_cli.rb +84 -0
- data/test/test_data_reader.rb +80 -0
- data/test/test_formatters.rb +120 -0
- data/test/test_ripper_tags.rb +218 -3
- metadata +55 -57
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MTY5YzNjZGUwOTNkOGMwMzM0NTY1MjE3ZDc4MDkyNjVkNjM2ZDBhNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MWM1M2IzYTk2ODgyZjEwZjQ5ODVlZDYzN2E1Nzc1NGEzOWRmYTI0Ng==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NDM5MWNkMjk2Y2YxODE2ZTMxODcyY2I3ODcwN2M1YmY5ODFjZGU1ZWI3Mjhj
|
10
|
+
YmIzMzAwMDcyZWM0ZmMxZTA3MTkxYTA0ODk1N2MwY2EwMzUxMTZmZDg1ZDQz
|
11
|
+
YzljYWE2NzEzZDY1YTVlOGQ0MDViNjJmYzBlMzJkNmYzZThkOTU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZWU2ZDQ5Nzc0MzAyNjNjYjI0YjU5MTczMjRkMDUwZTJiZWRhN2Y2Y2YwYmQz
|
14
|
+
Yzg5MDg3MDJkOTMzNzIyMmI2ZjQzNzliYmIwMzIyNzliNzYzMWQxNjFlZTMz
|
15
|
+
MDAxNzVlZjk2YmRjMDlhYTZiYTAzMDRkYjViNjFjYTNlNDgwZGI=
|
data/.gitignore
ADDED
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Aman Gupta
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -2,56 +2,26 @@
|
|
2
2
|
|
3
3
|
fast, accurate ctags generator for ruby source code using Ripper
|
4
4
|
|
5
|
-
### usage (
|
5
|
+
### usage (command-line)
|
6
|
+
|
7
|
+
Typical usage:
|
8
|
+
|
9
|
+
```
|
10
|
+
ripper-tags -R --exclude=vendor
|
11
|
+
```
|
12
|
+
|
13
|
+
This parses all `*.rb` files in the current project, excluding ones in `vendor/`
|
14
|
+
directory, and saves tags in Vim format to a file named `./tags`.
|
15
|
+
|
16
|
+
To see all available options:
|
6
17
|
|
7
18
|
```
|
8
|
-
|
9
|
-
30 module Timeout
|
10
|
-
35 class Timeout::Error < Interrupt
|
11
|
-
37 class Timeout::ExitException < Exception
|
12
|
-
40 const Timeout::THIS_FILE
|
13
|
-
41 const Timeout::CALLER_OFFSET
|
14
|
-
52 def Timeout#timeout
|
15
|
-
100 def Object#timeout
|
16
|
-
108 const TimeoutError
|
17
|
-
|
18
|
-
$ ripper-tags --debug /usr/lib/ruby/1.8/timeout.rb
|
19
|
-
[[:module,
|
20
|
-
["Timeout", 30],
|
21
|
-
[[:class, ["Error", 35], ["Interrupt", 35], []],
|
22
|
-
[:class, ["ExitException", 37], ["Exception", 37], []],
|
23
|
-
[:assign, "THIS_FILE", 40],
|
24
|
-
[:assign, "CALLER_OFFSET", 41],
|
25
|
-
[:def, "timeout", 52]]],
|
26
|
-
[:def, "timeout", 100],
|
27
|
-
[:assign, "TimeoutError", 108]]
|
28
|
-
|
29
|
-
$ ripper-tags --vim /usr/lib/ruby/1.8/timeout.rb
|
30
|
-
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
31
|
-
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
32
|
-
CALLER_OFFSET /usr/lib/ruby/1.8/timeout.rb /^ CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0$/;" C class:Timeout
|
33
|
-
Error /usr/lib/ruby/1.8/timeout.rb /^ class Error < Interrupt$/;" c class:Timeout inherits:Interrupt
|
34
|
-
ExitException /usr/lib/ruby/1.8/timeout.rb /^ class ExitException < ::Exception # :nodoc:$/;" c class:Timeout inherits:Exception
|
35
|
-
THIS_FILE /usr/lib/ruby/1.8/timeout.rb /^ THIS_FILE = \/\\A#{Regexp.quote(__FILE__)}:\/o$/;" C class:Timeout
|
36
|
-
Timeout /usr/lib/ruby/1.8/timeout.rb /^module Timeout$/;" m
|
37
|
-
TimeoutError /usr/lib/ruby/1.8/timeout.rb /^TimeoutError = Timeout::Error # :nodoc:$/;" C class:
|
38
|
-
timeout /usr/lib/ruby/1.8/timeout.rb /^def timeout(n, e = nil, &block) # :nodoc:$/;" f class:Object
|
39
|
-
timeout /usr/lib/ruby/1.8/timeout.rb /^ def timeout(sec, klass = nil)$/;" f class:Timeout
|
40
|
-
|
41
|
-
$ ripper-tags --json /usr/lib/ruby/1.8/timeout.rb
|
42
|
-
{"full_name":"Timeout","name":"Timeout","kind":"module","line":30,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":"module Timeout"}
|
43
|
-
{"full_name":"Timeout::Error","name":"Error","class":"Timeout","inherits":"Interrupt","kind":"class","line":35,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" class Error < Interrupt"}
|
44
|
-
{"full_name":"Timeout::ExitException","name":"ExitException","class":"Timeout","inherits":"Exception","kind":"class","line":37,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" class ExitException < ::Exception # :nodoc:"}
|
45
|
-
{"name":"THIS_FILE","full_name":"Timeout::THIS_FILE","class":"Timeout","kind":"constant","line":40,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" THIS_FILE = /\\A#{Regexp.quote(__FILE__)}:/o"}
|
46
|
-
{"name":"CALLER_OFFSET","full_name":"Timeout::CALLER_OFFSET","class":"Timeout","kind":"constant","line":41,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0"}
|
47
|
-
{"name":"timeout","full_name":"Timeout#timeout","class":"Timeout","kind":"method","line":52,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" def timeout(sec, klass = nil)"}
|
48
|
-
{"name":"timeout","full_name":"Object#timeout","class":"Object","kind":"method","line":100,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":"def timeout(n, e = nil, &block) # :nodoc:"}
|
49
|
-
{"name":"TimeoutError","full_name":"TimeoutError","class":"","kind":"constant","line":108,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":"TimeoutError = Timeout::Error # :nodoc:"}
|
19
|
+
ripper-tags --help
|
50
20
|
```
|
51
21
|
|
52
22
|
### usage (api)
|
53
23
|
|
54
24
|
``` ruby
|
55
|
-
require '
|
56
|
-
tags =
|
25
|
+
require 'ripper-tags/parser'
|
26
|
+
tags = RipperTags::Parser.extract("def abc() end", "mycode.rb")
|
57
27
|
```
|
data/bin/ripper-tags
CHANGED
@@ -1,98 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'ripper-tags'
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
trap(:INT) { abort }
|
5
|
+
trap(:PIPE) { abort }
|
5
6
|
|
6
|
-
|
7
|
-
require 'yajl'
|
8
|
-
json = true
|
9
|
-
end
|
10
|
-
if ARGV.delete('--debug')
|
11
|
-
debug = true
|
12
|
-
end
|
13
|
-
if ARGV.delete('--vim')
|
14
|
-
vim = true
|
15
|
-
all_tags = []
|
16
|
-
end
|
17
|
-
if ARGV.delete('--emacs')
|
18
|
-
emacs = true
|
19
|
-
end
|
20
|
-
if ARGV.delete('--debug-full')
|
21
|
-
debug_full = true
|
22
|
-
end
|
23
|
-
|
24
|
-
ARGV.each do |file|
|
25
|
-
begin
|
26
|
-
data = File.read(file)
|
27
|
-
sexp = TagRipper.new(data, file).parse
|
28
|
-
v = TagRipper::Visitor.new(sexp, file, data)
|
29
|
-
|
30
|
-
if debug_full
|
31
|
-
pp Ripper.sexp(data)
|
32
|
-
|
33
|
-
elsif debug
|
34
|
-
pp sexp
|
35
|
-
|
36
|
-
elsif json
|
37
|
-
v.tags.each do |tag|
|
38
|
-
puts Yajl.dump(tag)
|
39
|
-
end
|
40
|
-
|
41
|
-
elsif emacs
|
42
|
-
section = []
|
43
|
-
v.tags.each do |tag|
|
44
|
-
section << "#{tag[:pattern]}\x7F#{tag[:name]}\x01#{tag[:line]},0"
|
45
|
-
end
|
46
|
-
section = section.join("\n")
|
47
|
-
|
48
|
-
print "\x0C\n#{file},#{section.bytesize}\n#{section}\n"
|
49
|
-
|
50
|
-
elsif vim
|
51
|
-
all_tags += v.tags
|
52
|
-
|
53
|
-
else
|
54
|
-
v.tags.each do |tag|
|
55
|
-
kind = case tag[:kind]
|
56
|
-
when /method$/ then 'def'
|
57
|
-
when /^const/ then 'const'
|
58
|
-
else tag[:kind]
|
59
|
-
end
|
60
|
-
|
61
|
-
if kind == 'class' && tag[:inherits]
|
62
|
-
suffix = " < #{tag[:inherits]}"
|
63
|
-
else
|
64
|
-
suffix = ''
|
65
|
-
end
|
66
|
-
|
67
|
-
puts "#{tag[:line].to_s.rjust(5)} #{kind.to_s.rjust(6)} #{tag[:full_name]}#{suffix}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
rescue Exception => e
|
71
|
-
STDERR.puts [e, file].inspect
|
72
|
-
raise e
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
if vim
|
77
|
-
puts <<-EOC
|
78
|
-
!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;" to lines/
|
79
|
-
!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/
|
80
|
-
EOC
|
81
|
-
|
82
|
-
all_tags.sort_by!{ |t| t[:name] }
|
83
|
-
all_tags.each do |tag|
|
84
|
-
kwargs = ''
|
85
|
-
kwargs << "\tclass:#{tag[:class].gsub('::','.')}" if tag[:class]
|
86
|
-
kwargs << "\tinherits:#{tag[:inherits].gsub('::','.')}" if tag[:inherits]
|
87
|
-
|
88
|
-
kind = case tag[:kind]
|
89
|
-
when 'method' then 'f'
|
90
|
-
when 'singleton method' then 'F'
|
91
|
-
when 'constant' then 'C'
|
92
|
-
else tag[:kind].slice(0,1)
|
93
|
-
end
|
7
|
+
program_name = File.basename($0)
|
94
8
|
|
95
|
-
|
96
|
-
|
97
|
-
|
9
|
+
begin
|
10
|
+
RipperTags.process_args(ARGV)
|
11
|
+
rescue Errno::ENOENT, OptionParser::InvalidOption => err
|
12
|
+
abort "#{program_name}: #{err.message}"
|
98
13
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'ripper-tags/parser'
|
3
|
+
|
4
|
+
module RipperTags
|
5
|
+
class FileFinder
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def exclude_patterns
|
13
|
+
@exclude ||= Array(options.exclude).map { |pattern|
|
14
|
+
if pattern.index('*')
|
15
|
+
Regexp.new(Regexp.escape(pattern).gsub('\\*', '[^/]+'))
|
16
|
+
else
|
17
|
+
pattern
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def exclude_file?(file)
|
23
|
+
base = File.basename(file)
|
24
|
+
exclude_patterns.any? {|ex|
|
25
|
+
case ex
|
26
|
+
when Regexp then base =~ ex
|
27
|
+
else base == ex
|
28
|
+
end
|
29
|
+
} || exclude_patterns.any? {|ex|
|
30
|
+
case ex
|
31
|
+
when Regexp then file =~ ex
|
32
|
+
else file.include?(ex)
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def include_file?(file)
|
38
|
+
(options.all_files || file =~ /\.rb\z/) && !exclude_file?(file)
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_files(list, depth = 0)
|
42
|
+
list.each do |file|
|
43
|
+
if File.directory?(file)
|
44
|
+
if options.recursive
|
45
|
+
files = Dir.entries(file).map { |name|
|
46
|
+
File.join(file, name) unless '.' == name || '..' == name
|
47
|
+
}.compact
|
48
|
+
find_files(files, depth + 1) {|f| yield f }
|
49
|
+
end
|
50
|
+
else
|
51
|
+
yield file if include_file?(file)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def each_file
|
57
|
+
return to_enum(__method__) unless block_given?
|
58
|
+
find_files(options.files) {|f| yield f }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class DataReader
|
63
|
+
attr_reader :options
|
64
|
+
|
65
|
+
def initialize(options)
|
66
|
+
@options = options
|
67
|
+
end
|
68
|
+
|
69
|
+
def file_finder
|
70
|
+
FileFinder.new(options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def read_file(filename)
|
74
|
+
str = File.open(filename, 'r:utf-8') {|f| f.read }
|
75
|
+
normalize_encoding(str)
|
76
|
+
end
|
77
|
+
|
78
|
+
def normalize_encoding(str)
|
79
|
+
if str.respond_to?(:encode!)
|
80
|
+
# strip invalid byte sequences
|
81
|
+
str.encode!('utf-16', :invalid => :replace, :undef => :replace)
|
82
|
+
str.encode!('utf-8')
|
83
|
+
else
|
84
|
+
str
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def each_tag
|
89
|
+
return to_enum(__method__) unless block_given?
|
90
|
+
file_finder.each_file do |file|
|
91
|
+
begin
|
92
|
+
$stderr.puts "Parsing file #{file}" if options.verbose
|
93
|
+
extractor = tag_extractor(file)
|
94
|
+
rescue => err
|
95
|
+
if options.force
|
96
|
+
$stderr.puts "Error parsing `#{file}': #{err.message}"
|
97
|
+
else
|
98
|
+
raise err
|
99
|
+
end
|
100
|
+
else
|
101
|
+
extractor.tags.each do |tag|
|
102
|
+
yield tag
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def debug_dump(obj)
|
109
|
+
pp(obj, $stderr)
|
110
|
+
end
|
111
|
+
|
112
|
+
def parse_file(contents, filename)
|
113
|
+
sexp = Parser.new(contents, filename).parse
|
114
|
+
debug_dump(sexp) if options.debug
|
115
|
+
sexp
|
116
|
+
end
|
117
|
+
|
118
|
+
def tag_extractor(file)
|
119
|
+
file_contents = read_file(file)
|
120
|
+
debug_dump(Ripper.sexp(file_contents)) if options.verbose_debug
|
121
|
+
sexp = parse_file(file_contents, file)
|
122
|
+
Visitor.new(sexp, file, file_contents)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module RipperTags
|
4
|
+
class DefaultFormatter
|
5
|
+
attr_reader :options
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def stdout?
|
12
|
+
'-' == options.tag_file_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_output
|
16
|
+
if stdout?
|
17
|
+
yield $stdout
|
18
|
+
else
|
19
|
+
File.open(options.tag_file_name, 'w+') do |outfile|
|
20
|
+
yield outfile
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def tag_file_dir
|
26
|
+
@tag_file_dir ||= Pathname.new(options.tag_file_name).dirname
|
27
|
+
end
|
28
|
+
|
29
|
+
def relative_path(tag)
|
30
|
+
path = tag.fetch(:path)
|
31
|
+
if options.tag_relative && !stdout? && path.index('/') != 0
|
32
|
+
Pathname.new(path).relative_path_from(tag_file_dir).to_s
|
33
|
+
else
|
34
|
+
path
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def display_kind(tag)
|
39
|
+
case tag.fetch(:kind)
|
40
|
+
when /method$/ then 'def'
|
41
|
+
when /^const/ then 'const'
|
42
|
+
else tag[:kind]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def display_inheritance(tag)
|
47
|
+
if 'class' == tag[:kind] && tag[:inherits]
|
48
|
+
" < #{tag[:inherits]}"
|
49
|
+
else
|
50
|
+
""
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def format(tag)
|
55
|
+
"%5s %8s %s%s" % [
|
56
|
+
tag.fetch(:line).to_s,
|
57
|
+
display_kind(tag),
|
58
|
+
tag.fetch(:full_name),
|
59
|
+
display_inheritance(tag)
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
def write(tag, io)
|
64
|
+
io.puts format(tag)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'ripper-tags/default_formatter'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module RipperTags
|
5
|
+
# Generates etags format as described in
|
6
|
+
# https://en.wikipedia.org/wiki/Ctags#Etags_2
|
7
|
+
#
|
8
|
+
# The format is non-trivial since it requires section header for each source
|
9
|
+
# file to contain the size of tag data in bytes. This is accomplished by
|
10
|
+
# buffering tag definitions per-file and flushing them to target IO when a
|
11
|
+
# new source file is encountered or when `with_output` block finishes. This
|
12
|
+
# assumes that incoming tags are ordered by source file.
|
13
|
+
class EmacsFormatter < DefaultFormatter
|
14
|
+
def initialize(*)
|
15
|
+
super
|
16
|
+
@current_file = nil
|
17
|
+
@section_io = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def with_output
|
21
|
+
super do |io|
|
22
|
+
begin
|
23
|
+
yield io
|
24
|
+
ensure
|
25
|
+
flush_file_section(io)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(tag, io)
|
31
|
+
filename = relative_path(tag)
|
32
|
+
section_io = start_file_section(filename, io)
|
33
|
+
super(tag, section_io)
|
34
|
+
end
|
35
|
+
|
36
|
+
def start_file_section(filename, io)
|
37
|
+
if filename != @current_file
|
38
|
+
flush_file_section(io)
|
39
|
+
@current_file = filename
|
40
|
+
@section_io = StringIO.new
|
41
|
+
else
|
42
|
+
@section_io
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def flush_file_section(out)
|
47
|
+
if @section_io
|
48
|
+
data = @section_io.string
|
49
|
+
out.write format_section_header(@current_file, data)
|
50
|
+
out.write data
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def format_section_header(filename, data)
|
55
|
+
data_size = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
56
|
+
"\x0C\n%s,%d\n" % [ filename, data_size ]
|
57
|
+
end
|
58
|
+
|
59
|
+
def format(tag)
|
60
|
+
pattern = tag.fetch(:pattern)
|
61
|
+
"%s\x7F%s\x01%d,%d" % [
|
62
|
+
tag.fetch(:pattern),
|
63
|
+
tag.fetch(:name),
|
64
|
+
tag.fetch(:line),
|
65
|
+
0,
|
66
|
+
]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|