racknga 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,30 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ source "http://rubygems.org/"
19
+
20
+ gem "rroonga"
21
+ gem "rack"
22
+
23
+ group :development, :test do
24
+ gem "test-unit"
25
+ gem "test-unit-notify"
26
+ gem "test-unit-capybara"
27
+ gem "rake"
28
+ gem "jeweler"
29
+ gem "yard"
30
+ end
data/README.textile ADDED
@@ -0,0 +1,52 @@
1
+ h1. README
2
+
3
+ h2. Name
4
+
5
+ racknga
6
+
7
+ h2. Description
8
+
9
+ Rack middlewares that use rroonga features and
10
+ middlewares/utilities that don't use rroonga features.
11
+
12
+ * "rroonga":http://groonga.rubyforge.org/
13
+ * "Rack":http://rack.rubyforge.org/
14
+
15
+ h2. Authors
16
+
17
+ * Kouhei Sutou <kou@clear-code.com>
18
+
19
+ h2. License
20
+
21
+ LGPL 2.1 or later. See license/lgpl-2.1.txt for details.
22
+
23
+ (Kouhei Sutou has a right to change the license
24
+ including contributed patches.)
25
+
26
+ h2. Dependencies
27
+
28
+ * Ruby >= 1.9.1
29
+ * rroonga
30
+ * Rack
31
+
32
+ h2. Suggested libraries
33
+
34
+ * jpmobile
35
+
36
+ h2. Install
37
+
38
+ <pre>
39
+ % sudo gem install racknga
40
+ </pre>
41
+
42
+ h2. Documents
43
+
44
+ http://groonga.rubyforge.org/racknga/en/
45
+
46
+ h2. Mailing list
47
+
48
+ http://rubyforge.org/mailman/listinfo/groonga-users-en
49
+
50
+ h2. Thanks
51
+
52
+ * ...
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8; mode: ruby -*-
2
2
  #
3
- # Copyright (C) 2010 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2010-2011 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -17,21 +17,15 @@
17
17
 
18
18
  require 'English'
19
19
 
20
- require 'find'
21
20
  require 'fileutils'
22
21
  require 'pathname'
23
22
  require 'erb'
24
23
  require 'rubygems'
25
- gem 'rdoc'
26
- require 'hoe'
27
-
28
- ENV["NODOT"] = "yes"
29
-
30
- base_dir = Pathname(__FILE__).dirname
31
- truncate_base_dir = Proc.new do |path|
32
- path.relative_path_from(base_dir)
33
- end
24
+ require 'jeweler'
25
+ require "rake/clean"
26
+ require "yard"
34
27
 
28
+ base_dir = Pathname.new(__FILE__).dirname
35
29
  racknga_lib_dir = base_dir + 'lib'
36
30
  $LOAD_PATH.unshift(racknga_lib_dir.to_s)
37
31
 
@@ -40,150 +34,276 @@ def guess_version
40
34
  Racknga::VERSION
41
35
  end
42
36
 
43
- manifest = base_dir + "Manifest.txt"
44
- manifest_contents = []
45
- base_dir_included_components = %w(AUTHORS Rakefile
46
- README.rdoc README.ja.rdoc
47
- NEWS.rdoc NEWS.ja.rdoc
48
- rroonga-build.rb extconf.rb pkg-config.rb)
49
- excluded_components = %w(.cvsignore .gdb_history CVS depend Makefile doc pkg
50
- .svn .git doc data .test-result tmp)
51
- excluded_suffixes = %w(.png .ps .pdf .o .so .a .txt .~)
52
- unless ENV["RUBY_CC_VERSION"]
53
- excluded_components << "vendor"
54
- end
55
- base_dir.find do |target|
56
- target = truncate_base_dir[target]
57
- components = target.to_s.split(File::SEPARATOR)
58
- if components.size == 1 and !target.directory?
59
- next unless base_dir_included_components.include?(components[0])
37
+ ENV["VERSION"] ||= guess_version
38
+ version = ENV["VERSION"].dup
39
+ project = nil
40
+ spec = nil
41
+ Jeweler::Tasks.new do |_spec|
42
+ spec = _spec
43
+ spec.name = 'racknga'
44
+ spec.version = version
45
+ spec.rubyforge_project = 'groonga'
46
+ spec.homepage = "http://groonga.rubyforge.org/"
47
+ authors_file = File.join(base_dir, "AUTHORS")
48
+ authors = []
49
+ emails = []
50
+ File.readlines(authors_file).each do |line|
51
+ if /\s*<([^<>]*)>$/ =~ line
52
+ authors << $PREMATCH
53
+ emails << $1
54
+ end
60
55
  end
61
- Find.prune if (excluded_components - components) != excluded_components
62
- next if excluded_suffixes.include?(File.extname(target))
63
- manifest_contents << target if File.file?(target)
56
+ spec.authors = authors
57
+ spec.email = emails
58
+ spec.summary = "A Rack middleware collection for rroonga features."
59
+ spec.description = <<-EOD.gsub(/\n/, ' ').strip
60
+ Racknga is a Rack middlewares that uses rroonga features.
61
+ EOD
62
+ spec.license = "LGPLv2.1 or later"
63
+ spec.files = FileList["lib/**/*.rb",
64
+ "{license,munin,doc/text/}/**/*",
65
+ "example/*.rb",
66
+ "AUTHORS",
67
+ "Rakefile",
68
+ "Gemfile",
69
+ "README*"]
70
+ spec.test_files = FileList["test/**/*.rb"]
64
71
  end
65
72
 
66
- File.open(manifest, "w") do |f|
67
- f.puts manifest_contents.sort.join("\n")
73
+ Rake::Task["release"].prerequisites.clear
74
+ Jeweler::RubygemsDotOrgTasks.new do
68
75
  end
69
76
 
70
- # For Hoe's no user friendly default behavior. :<
71
- File.open("README.txt", "w") {|file| file << "= Dummy README\n== XXX\n"}
72
- FileUtils.cp("NEWS.rdoc", "History.txt")
73
- at_exit do
74
- FileUtils.rm_f("README.txt")
75
- FileUtils.rm_f("History.txt")
76
- FileUtils.rm_f(manifest)
77
+ reference_base_dir = Pathname.new("doc/reference")
78
+ doc_en_dir = reference_base_dir + "en"
79
+ html_base_dir = Pathname.new("doc/html")
80
+ html_reference_dir = html_base_dir + spec.name
81
+ YARD::Rake::YardocTask.new do |task|
82
+ task.options += ["--title", spec.name]
83
+ task.options += ["--readme", "README.textile"]
84
+ task.options += ["--files", "doc/text/**/*"]
85
+ task.options += ["--output-dir", doc_en_dir.to_s]
86
+ task.options += ["--charset", "utf-8"]
77
87
  end
78
88
 
79
- def cleanup_white_space(entry)
80
- entry.gsub(/(\A\n+|\n+\z)/, '') + "\n"
81
- end
82
-
83
- ENV["VERSION"] ||= guess_version
84
- version = ENV["VERSION"]
85
- project = nil
86
- Hoe.spec('racknga') do
87
- Hoe::Test::SUPPORTED_TEST_FRAMEWORKS[:testunit2] = "test/run-test.rb"
88
- project = self
89
- project.version = version.dup
90
- project.rubyforge_name = 'groonga'
91
- authors = File.join(base_dir, "AUTHORS")
92
- project.author = File.readlines(authors).collect do |line|
93
- if /\s*<[^<>]*>$/ =~ line
94
- $PREMATCH
95
- else
96
- nil
89
+ task :yard do
90
+ doc_en_dir.find do |path|
91
+ next if path.extname != ".html"
92
+ html = path.read
93
+ html = html.gsub(/<div id="footer">.+<\/div>/m,
94
+ "<div id=\"footer\"></div>")
95
+ path.open("w") do |html_file|
96
+ html_file.print(html)
97
97
  end
98
- end.compact
99
- project.email = ['groonga-users-en@rubyforge.org',
100
- 'groonga-dev@lists.sourceforge.jp']
101
- project.url = 'http://groonga.rubyforge.org/'
102
- project.testlib = :testunit2
103
- project.test_globs = ["test/run-test.rb"]
104
- project.extra_deps += [["rroonga"],
105
- ["rack"]]
106
- project.spec_extras = {
107
- :extra_rdoc_files => Dir.glob("**/*.rdoc"),
108
- :licenses => ["LGPL 2.1 or later"]
109
- }
110
- project.readme_file = "README.ja.rdoc"
111
-
112
- news_of_current_release = File.read("NEWS.rdoc").split(/^==\s.*$/)[1]
113
- project.changes = cleanup_white_space(news_of_current_release)
114
-
115
- entries = File.read("README.rdoc").split(/^==\s(.*)$/)
116
- description = cleanup_white_space(entries[entries.index("Description") + 1])
117
- project.summary, project.description, = description.split(/\n\n+/, 3)
118
-
119
- project.remote_rdoc_dir = "racknga"
120
- end
121
-
122
- ObjectSpace.each_object(Rake::RDocTask) do |rdoc_task|
123
- options = rdoc_task.options
124
- t_option_index = options.index("--title") || options.index("-t")
125
- rdoc_task.options[t_option_index, 2] = [] if t_option_index
126
- rdoc_task.title = "racknga - #{version}"
98
+ end
127
99
  end
128
100
 
129
- task :publish_docs => [:prepare_docs_for_publishing]
130
-
131
-
132
101
  include ERB::Util
133
102
 
134
- def apply_template(file, head, header, footer)
135
- content = File.read(file)
136
- content = content.sub(/lang="en"/, 'lang="ja"')
103
+ def apply_template(content, paths, templates, language)
104
+ content = content.sub(/lang="en"/, "lang=\"#{language}\"")
137
105
 
138
106
  title = nil
139
- content = content.sub(/<title>(.+?)<\/title>/) do
107
+ content = content.sub(/<title>(.+?)<\/title>/m) do
140
108
  title = $1
141
- head.result(binding)
109
+ templates[:head].result(binding)
142
110
  end
143
111
 
144
112
  content = content.sub(/<body(?:.*?)>/) do |body_start|
145
- "#{body_start}\n#{header.result(binding)}\n"
113
+ "#{body_start}\n#{templates[:header].result(binding)}\n"
146
114
  end
147
115
 
148
116
  content = content.sub(/<\/body/) do |body_end|
149
- "\n#{footer.result(binding)}\n#{body_end}"
117
+ "\n#{templates[:footer].result(binding)}\n#{body_end}"
150
118
  end
151
119
 
152
- File.open(file, "w") do |file|
153
- file.print(content)
154
- end
120
+ content
155
121
  end
156
122
 
157
123
  def erb_template(name)
158
- file = File.join("html", "#{name}.html.erb")
124
+ file = File.join("doc/templates", "#{name}.html.erb")
159
125
  template = File.read(file)
160
126
  erb = ERB.new(template, nil, "-")
161
127
  erb.filename = file
162
128
  erb
163
129
  end
164
130
 
165
- task :prepare_docs_for_publishing do
166
- head = erb_template("head")
167
- header = erb_template("header")
168
- footer = erb_template("footer")
169
- Find.find("doc") do |file|
170
- if /\.html\z/ =~ file and /_(?:c|rb)\.html\z/ !~ file
171
- apply_template(file, head, header, footer)
131
+ def rsync_to_rubyforge(spec, source, destination, options={})
132
+ config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
133
+ host = "#{config["username"]}@rubyforge.org"
134
+
135
+ rsync_args = "-av --exclude '*.erb' --chmod=ug+w"
136
+ rsync_args << " --delete" if options[:delete]
137
+ remote_dir = "/var/www/gforge-projects/#{spec.rubyforge_project}/"
138
+ sh("rsync #{rsync_args} #{source} #{host}:#{remote_dir}#{destination}")
139
+ end
140
+
141
+ def rake(*arguments)
142
+ ruby($0, *arguments)
143
+ end
144
+
145
+ namespace :reference do
146
+ translate_languages = [:ja]
147
+ supported_languages = [:en, *translate_languages]
148
+ html_files = FileList[doc_en_dir + "**/*.html"].to_a
149
+
150
+ directory reference_base_dir.to_s
151
+ CLOBBER.include(reference_base_dir.to_s)
152
+
153
+ po_dir = "doc/po"
154
+ pot_file = "#{po_dir}/#{spec.name}.pot"
155
+ namespace :pot do
156
+ directory po_dir
157
+ file pot_file => [po_dir, *html_files] do |t|
158
+ sh("xml2po", "--keep-entities", "--output", t.name, *html_files)
172
159
  end
160
+
161
+ desc "Generates pot file."
162
+ task :generate => pot_file
173
163
  end
174
- end
175
164
 
176
- task :publish_html do
177
- config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
178
- host = "#{config["username"]}@rubyforge.org"
165
+ namespace :po do
166
+ translate_languages.each do |language|
167
+ namespace language do
168
+ po_file = "#{po_dir}/#{language}.po"
169
+
170
+ if File.exist?(po_file)
171
+ file po_file => html_files do |t|
172
+ sh("xml2po", "--keep-entities", "--update", t.name, *html_files)
173
+ end
174
+ else
175
+ file po_file => pot_file do |t|
176
+ sh("msginit",
177
+ "--input=#{pot_file}",
178
+ "--output=#{t.name}",
179
+ "--locale=#{language}")
180
+ end
181
+ end
182
+
183
+ desc "Updates po file for #{language}."
184
+ task :update => po_file
185
+ end
186
+ end
187
+
188
+ desc "Updates po files."
189
+ task :update do
190
+ rake("clobber")
191
+ rake("yard")
192
+ translate_languages.each do |language|
193
+ rake("reference:po:#{language}:update")
194
+ end
195
+ end
196
+ end
197
+
198
+ namespace :translate do
199
+ translate_languages.each do |language|
200
+ po_file = "#{po_dir}/#{language}.po"
201
+ translate_doc_dir = "#{reference_base_dir}/#{language}"
202
+
203
+ desc "Translates documents to #{language}."
204
+ task language => [po_file, reference_base_dir, *html_files] do
205
+ doc_en_dir.find do |path|
206
+ base_path = path.relative_path_from(doc_en_dir)
207
+ translated_path = "#{translate_doc_dir}/#{base_path}"
208
+ if path.directory?
209
+ mkdir_p(translated_path)
210
+ next
211
+ end
212
+ case path.extname
213
+ when ".html"
214
+ sh("xml2po --keep-entities " +
215
+ "--po-file #{po_file} --language #{language} " +
216
+ "#{path} > #{translated_path}")
217
+ else
218
+ cp(path.to_s, translated_path, :preserve => true)
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ translate_task_names = translate_languages.collect do |language|
226
+ "reference:translate:#{language}"
227
+ end
228
+ desc "Translates references."
229
+ task :translate => translate_task_names
230
+
231
+ desc "Generates references."
232
+ task :generate => [:yard, :translate]
233
+
234
+ namespace :publication do
235
+ task :prepare do
236
+ supported_languages.each do |language|
237
+ raw_reference_dir = reference_base_dir + language.to_s
238
+ prepared_reference_dir = html_reference_dir + language.to_s
239
+ rm_rf(prepared_reference_dir.to_s)
240
+ head = erb_template("head.#{language}")
241
+ header = erb_template("header.#{language}")
242
+ footer = erb_template("footer.#{language}")
243
+ raw_reference_dir.find do |path|
244
+ relative_path = path.relative_path_from(raw_reference_dir)
245
+ prepared_path = prepared_reference_dir + relative_path
246
+ if path.directory?
247
+ mkdir_p(prepared_path.to_s)
248
+ else
249
+ case path.basename.to_s
250
+ when /(?:file|method|class)_list\.html\z/
251
+ cp(path.to_s, prepared_path.to_s)
252
+ when /\.html\z/
253
+ relative_dir_path = relative_path.dirname
254
+ current_path = relative_dir_path + path.basename
255
+ if current_path.basename.to_s == "index.html"
256
+ current_path = current_path.dirname
257
+ end
258
+ top_path = html_base_dir.relative_path_from(prepared_path.dirname)
259
+ package_path = top_path + spec.name
260
+ paths = {
261
+ :top => top_path,
262
+ :current => current_path,
263
+ :package => package_path,
264
+ }
265
+ templates = {
266
+ :head => head,
267
+ :header => header,
268
+ :footer => footer
269
+ }
270
+ content = apply_template(File.read(path.to_s),
271
+ paths,
272
+ templates,
273
+ language)
274
+ File.open(prepared_path.to_s, "w") do |file|
275
+ file.print(content)
276
+ end
277
+ else
278
+ cp(path.to_s, prepared_path.to_s)
279
+ end
280
+ end
281
+ end
282
+ end
283
+ File.open("#{html_reference_dir}/.htaccess", "w") do |file|
284
+ file.puts("RedirectMatch permanent ^/#{spec.name}/$ " +
285
+ "#{spec.homepage}#{spec.name}/en/")
286
+ end
287
+ end
288
+ end
179
289
 
180
- rsync_args = "-av --exclude '*.erb' --exclude '*.svg' --exclude .svn"
181
- remote_dir = "/var/www/gforge-projects/#{project.rubyforge_name}/"
182
- sh "rsync #{rsync_args} html/ #{host}:#{remote_dir}"
290
+ desc "Upload document to rubyforge."
291
+ task :publish => [:generate, "reference:publication:prepare"] do
292
+ rsync_to_rubyforge(spec, "#{html_reference_dir}/", spec.name)
293
+ end
294
+ end
295
+
296
+ namespace :html do
297
+ desc "Publish HTML to Web site."
298
+ task :publish do
299
+ rsync_to_rubyforge(spec, "#{html_base_dir}/", "")
300
+ end
183
301
  end
184
302
 
303
+ desc "Upload document to rubyforge."
304
+ task :publish => ["reference:publish"]
305
+
306
+ desc "Tag the current revision."
185
307
  task :tag do
186
308
  sh("git tag -a #{version} -m 'release #{version}!!!'")
187
309
  end
188
-
189
- task(:release).prerequisites.reject! {|name| name == "clean"}
@@ -0,0 +1,32 @@
1
+ h1. NEWS
2
+
3
+ h2. 0.9.2: 2011-08-07
4
+
5
+ h3. Improvments
6
+
7
+ * [munin] Supported Passenger 3 support.
8
+ * [munin] Removed Passenger 2 support.
9
+ * [middleware][jsonp] Improved browser compatibility by using
10
+ "text/javascript" for Content-Type.
11
+ * [middleware][cache] Improved checksum robustness by using
12
+ SHA1 instead of MD5.
13
+ * [middleware][cache] Supported 4096 >= length URL.
14
+ * [exception-mail-notifier] Supported limited mailing.
15
+ * [middleware][instance-name] Added.
16
+ * Added NginixAccessLogParser.
17
+ * Documented middlewares.
18
+
19
+ h2. 0.9.1: 2010-11-11
20
+
21
+ * Improved cache validation.
22
+ * Supported caches per User-Agent.
23
+ * Added a JSONP middleware.
24
+ * Added a HTTP Range support middleware.
25
+ * Added a logging access to groogna databsae middleware.
26
+ * Added Munin plugins for Passenger.
27
+ * Changed license to LGPLv2.1 or later from LGPLv2.1.
28
+ * Supported will_paginate.
29
+
30
+ h2. 0.9.0: 2010-07-04
31
+
32
+ * Initial release!
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2010 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2010-2011 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -21,7 +21,13 @@ require 'fileutils'
21
21
  require 'groonga'
22
22
 
23
23
  module Racknga
24
+ # This is a cache database based on groonga. It is used by
25
+ # Racknga::Middleware::Cache.
26
+ #
27
+ # Normally, #purge_old_responses is only used for cache
28
+ # maintenance.
24
29
  class CacheDatabase
30
+ # @param [String] database_path the path for cache database.
25
31
  def initialize(database_path)
26
32
  @database_path = database_path
27
33
  @context = Groonga::Context.new(:encoding => :none)
@@ -40,14 +46,23 @@ module Racknga
40
46
  configurations["default"]
41
47
  end
42
48
 
49
+ # Purges old responses. To clear old caches, you should
50
+ # call this method periodically or after data update.
51
+ #
52
+ # You can call this method by the different
53
+ # process from your Rack application
54
+ # process. (e.g. cron.) It's multi process safe.
43
55
  def purge_old_responses
44
56
  age_modulo = 2 ** 32
45
57
  age = configuration.age
46
58
  previous_age = (age - 1).modulo(age_modulo)
47
59
  configuration.age = (age + 1).modulo(age_modulo)
48
60
 
49
- responses.each do |response|
50
- response.delete if response.age == previous_age
61
+ target_responses = responses.select do |record|
62
+ record.age == previous_age
63
+ end
64
+ target_responses.each do |response|
65
+ response.key.delete
51
66
  end
52
67
  end
53
68