lru 0.1.0
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/History.txt +6 -0
- data/License.txt +20 -0
- data/Manifest.txt +25 -0
- data/README.txt +29 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +70 -0
- data/config/requirements.rb +17 -0
- data/init.rb +21 -0
- data/lib/lru.rb +193 -0
- data/lib/test.rb +5 -0
- data/lib/test/version.rb +9 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +9 -0
- data/test/test_helper.rb +2 -0
- data/test/test_lru.rb +58 -0
- data/website/index.html +11 -0
- data/website/index.txt +39 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +77 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 FIXME full name
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
init.rb
|
2
|
+
History.txt
|
3
|
+
License.txt
|
4
|
+
Manifest.txt
|
5
|
+
README.txt
|
6
|
+
Rakefile
|
7
|
+
config/hoe.rb
|
8
|
+
config/requirements.rb
|
9
|
+
lib/test.rb
|
10
|
+
lib/lru.rb
|
11
|
+
lib/test/version.rb
|
12
|
+
script/destroy
|
13
|
+
script/generate
|
14
|
+
script/txt2html
|
15
|
+
setup.rb
|
16
|
+
tasks/deployment.rake
|
17
|
+
tasks/environment.rake
|
18
|
+
tasks/website.rake
|
19
|
+
test/test_helper.rb
|
20
|
+
test/test_lru.rb
|
21
|
+
website/index.html
|
22
|
+
website/index.txt
|
23
|
+
website/javascripts/rounded_corners_lite.inc.js
|
24
|
+
website/stylesheets/screen.css
|
25
|
+
website/template.rhtml
|
data/README.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
= Efficient LRU Cache in Ruby
|
2
|
+
|
3
|
+
This class implements an LRU Cache where all operations are
|
4
|
+
implemented in constant time. This is in contract to other classes,
|
5
|
+
e.g. ruby-cache, whose operations complete in Order(n) time. The
|
6
|
+
primary implementation details for this class include:
|
7
|
+
|
8
|
+
- Simple API. We do not provide a complete Hash API, but do provide
|
9
|
+
enumerable and common shortcuts.
|
10
|
+
|
11
|
+
- True linked list underlying the LRU. Ruby-cache uses a ruby array
|
12
|
+
and traverses ALL elements for key operations (like get).
|
13
|
+
|
14
|
+
- No aggressive cache flushing. Items are expired only once the
|
15
|
+
cache reaches the capacity you configured. There is no garbage
|
16
|
+
collection or other process that can delay operations. Every
|
17
|
+
access to the cache occurs in constant time.
|
18
|
+
|
19
|
+
== Usage
|
20
|
+
require 'lru'
|
21
|
+
cache = Cache::LRU.new(:max_elements => 5)
|
22
|
+
cache.put(:a, 1)
|
23
|
+
cache[:a] = 2
|
24
|
+
cache.get(:b) { 1 }
|
25
|
+
cache[:b]
|
26
|
+
|
27
|
+
== Authors
|
28
|
+
Michael Bryzek mbryzek<at>alum.mit.edu
|
29
|
+
Phong Nguyen phong<at>gilt.com
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'test/version'
|
2
|
+
|
3
|
+
AUTHOR = ['Michael Bryzek', 'Phong Nguyen'] # can also be an array of Authors
|
4
|
+
EMAIL = "mbryzek@alum.mit.edu"
|
5
|
+
DESCRIPTION = "Efficient LRU in pure ruby where all operations are constant time"
|
6
|
+
GEM_NAME = 'lru' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'lru' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
|
11
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
12
|
+
@config = nil
|
13
|
+
RUBYFORGE_USERNAME = "unknown"
|
14
|
+
def rubyforge_username
|
15
|
+
unless @config
|
16
|
+
begin
|
17
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
18
|
+
rescue
|
19
|
+
puts <<-EOS
|
20
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
21
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
22
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
23
|
+
EOS
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
REV = nil
|
32
|
+
# UNCOMMENT IF REQUIRED:
|
33
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
|
+
VERS = Test::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
+
RDOC_OPTS = ['--quiet', '--title', 'test documentation',
|
36
|
+
"--opname", "index.html",
|
37
|
+
"--line-numbers",
|
38
|
+
"--main", "README",
|
39
|
+
"--inline-source"]
|
40
|
+
|
41
|
+
class Hoe
|
42
|
+
def extra_deps
|
43
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
44
|
+
@extra_deps
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generate all the Rake tasks
|
49
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
50
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
51
|
+
p.author = AUTHOR
|
52
|
+
p.description = DESCRIPTION
|
53
|
+
p.email = EMAIL
|
54
|
+
p.summary = DESCRIPTION
|
55
|
+
p.url = HOMEPATH
|
56
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
57
|
+
p.test_globs = ["test/**/test_*.rb"]
|
58
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
59
|
+
|
60
|
+
# == Optional
|
61
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
|
62
|
+
#p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
63
|
+
|
64
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
69
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
70
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'test'
|
data/init.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright (c) 2007 Michael Bryzek
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'lru'
|
data/lib/lru.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# Copyright (c) 2007 Michael Bryzek
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
#
|
21
|
+
module Cache
|
22
|
+
|
23
|
+
# Defines a local LRU cache. All operations are maintained in
|
24
|
+
# constant size regardless of the size of the Cache. When creating
|
25
|
+
# the cache, you specify the max size of the cache.
|
26
|
+
#
|
27
|
+
# Example:
|
28
|
+
# cache = Cache::LRU.new(:max_elements => 5)
|
29
|
+
# cache.put(:a, 1)
|
30
|
+
# cache[:a] = 2
|
31
|
+
# cache.get(:b) { 1 }
|
32
|
+
# cache[:b]
|
33
|
+
class LRU
|
34
|
+
|
35
|
+
include Enumerable
|
36
|
+
|
37
|
+
attr_reader :size
|
38
|
+
attr_reader :keys
|
39
|
+
# opts:
|
40
|
+
# - max_elements - maximum number of elements to keep in the
|
41
|
+
# cache at any time. The default is 100 elements
|
42
|
+
def initialize(opts = {})
|
43
|
+
opts = { :max_elements => 100 }.merge(opts)
|
44
|
+
@max_elements = opts.delete(:max_elements)
|
45
|
+
raise "Invalid options: #{opts.keys.join(' ')}" if opts.keys.size > 0
|
46
|
+
@keys = LinkedList.new
|
47
|
+
@map = {}
|
48
|
+
@size = 0
|
49
|
+
end
|
50
|
+
|
51
|
+
def clear!
|
52
|
+
initialize( :max_elements => @max_elements )
|
53
|
+
end
|
54
|
+
|
55
|
+
# Iterates through all of the key/value pairs added to the cache,
|
56
|
+
# in random order. Accepts a block that is yielded to with the key
|
57
|
+
# and value for each entry in the cache.
|
58
|
+
def each
|
59
|
+
@map.each do |k, el|
|
60
|
+
yield k, el.value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def [](key)
|
65
|
+
get(key)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Fetches the value of the element with the given key. If this key
|
69
|
+
# does not exist in the cache, you can provide an optional code
|
70
|
+
# block that we'll yield to to repopulate the value
|
71
|
+
def get(key)
|
72
|
+
if el = @map[key]
|
73
|
+
@keys.move_to_head(el)
|
74
|
+
return el.value
|
75
|
+
elsif block_given?
|
76
|
+
return put(key, yield)
|
77
|
+
end
|
78
|
+
return nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def []=(key, value)
|
82
|
+
put(key, value)
|
83
|
+
end
|
84
|
+
|
85
|
+
def put(key, value)
|
86
|
+
el = @map[key]
|
87
|
+
if el
|
88
|
+
el.value = value
|
89
|
+
@keys.move_to_head(el)
|
90
|
+
else
|
91
|
+
el = @keys.add(key, value)
|
92
|
+
@size += 1
|
93
|
+
end
|
94
|
+
@map[key] = el
|
95
|
+
|
96
|
+
if @size > @max_elements
|
97
|
+
delete_element(@keys.last)
|
98
|
+
@size -= 1
|
99
|
+
end
|
100
|
+
value
|
101
|
+
end
|
102
|
+
|
103
|
+
def delete(key)
|
104
|
+
if el = @map[key]
|
105
|
+
delete_element(el)
|
106
|
+
@size -= 1
|
107
|
+
else
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
def delete_element(el)
|
114
|
+
@keys.remove_element(el)
|
115
|
+
@map.delete(el.key)
|
116
|
+
el.value
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
class LinkedList
|
122
|
+
|
123
|
+
attr_reader :last
|
124
|
+
def initialize
|
125
|
+
@head = @last = nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def add(key, value)
|
129
|
+
add_element(Element.new(key, value, @head))
|
130
|
+
end
|
131
|
+
|
132
|
+
def add_element(el)
|
133
|
+
@head.previous_element = el if @head
|
134
|
+
|
135
|
+
el.next_element = @head
|
136
|
+
el.previous_element = nil
|
137
|
+
@head = el
|
138
|
+
@last = el unless @last
|
139
|
+
el
|
140
|
+
end
|
141
|
+
|
142
|
+
def remove_element(el)
|
143
|
+
el.previous_element.next_element = el.next_element if el.previous_element
|
144
|
+
el.next_element.previous_element = el.previous_element if el.next_element
|
145
|
+
|
146
|
+
@last = el.previous_element if el == @last
|
147
|
+
@head = el.next_element if el == @head
|
148
|
+
end
|
149
|
+
|
150
|
+
def move_to_head(el)
|
151
|
+
remove_element(el)
|
152
|
+
add_element(el)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns a nicely formatted stirng of all elements in the linked
|
156
|
+
# list. First element is most recently used, last element is least
|
157
|
+
# recently used.
|
158
|
+
def pp
|
159
|
+
s = ''
|
160
|
+
el = @head
|
161
|
+
while el
|
162
|
+
s << ', ' if s.size > 0
|
163
|
+
s << el.to_s
|
164
|
+
el = el.next_element
|
165
|
+
end
|
166
|
+
s
|
167
|
+
end
|
168
|
+
|
169
|
+
class Element
|
170
|
+
|
171
|
+
attr_accessor :key, :value, :previous_element, :next_element
|
172
|
+
def initialize(key, value, next_element)
|
173
|
+
@key = key
|
174
|
+
@value = value
|
175
|
+
@next_element = next_element
|
176
|
+
@previous_element = nil
|
177
|
+
end
|
178
|
+
|
179
|
+
def inspect
|
180
|
+
to_s
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_s
|
184
|
+
p = @previous_element ? @previous_element.key : 'nil'
|
185
|
+
n = @next_element ? @next_element.key : 'nil'
|
186
|
+
"[#{@key}: #{@value.inspect}, previous: #{p}, next: #{n}]"
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
data/lib/test.rb
ADDED
data/lib/test/version.rb
ADDED
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.join(File.dirname(__FILE__), '..')
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.join(File.dirname(__FILE__), '..')
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/script/txt2html
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
begin
|
5
|
+
require 'newgem'
|
6
|
+
rescue LoadError
|
7
|
+
puts "\n\nGenerating the website requires the newgem RubyGem"
|
8
|
+
puts "Install: gem install newgem\n\n"
|
9
|
+
exit(1)
|
10
|
+
end
|
11
|
+
require 'redcloth'
|
12
|
+
require 'syntax/convertors/html'
|
13
|
+
require 'erb'
|
14
|
+
require File.dirname(__FILE__) + '/../lib/test/version.rb'
|
15
|
+
|
16
|
+
version = Test::VERSION::STRING
|
17
|
+
download = 'http://rubyforge.org/projects/test'
|
18
|
+
|
19
|
+
class Fixnum
|
20
|
+
def ordinal
|
21
|
+
# teens
|
22
|
+
return 'th' if (10..19).include?(self % 100)
|
23
|
+
# others
|
24
|
+
case self % 10
|
25
|
+
when 1: return 'st'
|
26
|
+
when 2: return 'nd'
|
27
|
+
when 3: return 'rd'
|
28
|
+
else return 'th'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Time
|
34
|
+
def pretty
|
35
|
+
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def convert_syntax(syntax, source)
|
40
|
+
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
41
|
+
end
|
42
|
+
|
43
|
+
if ARGV.length >= 1
|
44
|
+
src, template = ARGV
|
45
|
+
template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml')
|
46
|
+
|
47
|
+
else
|
48
|
+
puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
|
49
|
+
exit!
|
50
|
+
end
|
51
|
+
|
52
|
+
template = ERB.new(File.open(template).read)
|
53
|
+
|
54
|
+
title = nil
|
55
|
+
body = nil
|
56
|
+
File.open(src) do |fsrc|
|
57
|
+
title_text = fsrc.readline
|
58
|
+
body_text = fsrc.read
|
59
|
+
syntax_items = []
|
60
|
+
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
|
61
|
+
ident = syntax_items.length
|
62
|
+
element, syntax, source = $1, $2, $3
|
63
|
+
syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
|
64
|
+
"syntax-temp-#{ident}"
|
65
|
+
}
|
66
|
+
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
67
|
+
body = RedCloth.new(body_text).to_html
|
68
|
+
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
|
69
|
+
end
|
70
|
+
stat = File.stat(src)
|
71
|
+
created = stat.ctime
|
72
|
+
modified = stat.mtime
|
73
|
+
|
74
|
+
$stdout << template.result(binding)
|