sinatra-s3 0.98
Sign up to get free protection for your applications and to get access to all the features.
- data/README +23 -0
- data/Rakefile +51 -0
- data/bin/sinatra-s3 +30 -0
- data/db/migrate/001_create_bits.rb +28 -0
- data/db/migrate/002_create_users.rb +24 -0
- data/db/migrate/003_create_bits_users.rb +16 -0
- data/db/migrate/004_create_torrents.rb +22 -0
- data/db/migrate/005_create_torrent_peers.rb +26 -0
- data/examples/README +9 -0
- data/examples/wiki.rb +199 -0
- data/examples/wiki.ru +5 -0
- data/examples/wikicloth/MIT-LICENSE +20 -0
- data/examples/wikicloth/README +81 -0
- data/examples/wikicloth/Rakefile +23 -0
- data/examples/wikicloth/init.rb +1 -0
- data/examples/wikicloth/install.rb +0 -0
- data/examples/wikicloth/lib/core_ext.rb +43 -0
- data/examples/wikicloth/lib/wiki_buffer/html_element.rb +237 -0
- data/examples/wikicloth/lib/wiki_buffer/link.rb +70 -0
- data/examples/wikicloth/lib/wiki_buffer/table.rb +159 -0
- data/examples/wikicloth/lib/wiki_buffer/var.rb +77 -0
- data/examples/wikicloth/lib/wiki_buffer.rb +279 -0
- data/examples/wikicloth/lib/wiki_cloth.rb +61 -0
- data/examples/wikicloth/lib/wiki_link_handler.rb +138 -0
- data/examples/wikicloth/lib/wikicloth.rb +5 -0
- data/examples/wikicloth/run_tests.rb +48 -0
- data/examples/wikicloth/sample_documents/air_force_one.wiki +170 -0
- data/examples/wikicloth/sample_documents/cheatsheet.wiki +205 -0
- data/examples/wikicloth/sample_documents/default.css +34 -0
- data/examples/wikicloth/sample_documents/elements.wiki +7 -0
- data/examples/wikicloth/sample_documents/george_washington.wiki +526 -0
- data/examples/wikicloth/sample_documents/images.wiki +15 -0
- data/examples/wikicloth/sample_documents/lists.wiki +421 -0
- data/examples/wikicloth/sample_documents/pipe_trick.wiki +68 -0
- data/examples/wikicloth/sample_documents/random.wiki +55 -0
- data/examples/wikicloth/sample_documents/tv.wiki +312 -0
- data/examples/wikicloth/sample_documents/wiki.png +0 -0
- data/examples/wikicloth/sample_documents/wiki_tables.wiki +410 -0
- data/examples/wikicloth/tasks/wikicloth_tasks.rake +0 -0
- data/examples/wikicloth/test/test_helper.rb +3 -0
- data/examples/wikicloth/test/wiki_cloth_test.rb +8 -0
- data/examples/wikicloth/uninstall.rb +0 -0
- data/examples/wikicloth/wikicloth-0.1.3.gem +0 -0
- data/examples/wikicloth/wikicloth.gemspec +69 -0
- data/lib/sinatra-s3/admin.rb +626 -0
- data/lib/sinatra-s3/base.rb +526 -0
- data/lib/sinatra-s3/errors.rb +51 -0
- data/lib/sinatra-s3/ext.rb +20 -0
- data/lib/sinatra-s3/helpers/acp.rb +100 -0
- data/lib/sinatra-s3/helpers/admin.rb +41 -0
- data/lib/sinatra-s3/helpers/tracker.rb +42 -0
- data/lib/sinatra-s3/helpers/versioning.rb +27 -0
- data/lib/sinatra-s3/helpers.rb +79 -0
- data/lib/sinatra-s3/models/bit.rb +180 -0
- data/lib/sinatra-s3/models/bucket.rb +81 -0
- data/lib/sinatra-s3/models/file_info.rb +3 -0
- data/lib/sinatra-s3/models/git_bucket.rb +3 -0
- data/lib/sinatra-s3/models/slot.rb +47 -0
- data/lib/sinatra-s3/models/torrent.rb +6 -0
- data/lib/sinatra-s3/models/torrent_peer.rb +5 -0
- data/lib/sinatra-s3/models/user.rb +35 -0
- data/lib/sinatra-s3/s3.rb +57 -0
- data/lib/sinatra-s3/tasks.rb +62 -0
- data/lib/sinatra-s3/tracker.rb +134 -0
- data/lib/sinatra-s3.rb +1 -0
- data/public/css/control.css +225 -0
- data/public/css/wiki.css +47 -0
- data/public/images/external-link.gif +0 -0
- data/public/js/prototype.js +2539 -0
- data/public/js/upload_status.js +117 -0
- data/public/test.html +8 -0
- data/s3.yml.example +17 -0
- data/test/s3api_test.rb +121 -0
- data/test/test_helper.rb +25 -0
- metadata +156 -0
data/README
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
An implementation of the S3 API in Sinatra. Most of the code was originaly taken from
|
2
|
+
ParkPlace, another S3 clone written by _why.
|
3
|
+
|
4
|
+
Requirements
|
5
|
+
-------------------------------------------------------
|
6
|
+
|
7
|
+
gem install sinatra haml aws-s3
|
8
|
+
|
9
|
+
Optional Torrent Support
|
10
|
+
-------------------------------------------------------
|
11
|
+
|
12
|
+
If you are interested in using Sinatra-S3 as a Bittorrent tracker you will need a custom
|
13
|
+
version of RubyTorrent found at http://github.com/nricciar/rubytorrent.
|
14
|
+
|
15
|
+
Install
|
16
|
+
-------------------------------------------------------
|
17
|
+
|
18
|
+
1) cp s3.yml.example s3.yml
|
19
|
+
2) edit s3.yml to suit your needs
|
20
|
+
3) rake db:migrate
|
21
|
+
4) rackup config.ru -p 6060
|
22
|
+
5) go to http://localhost:6060/control/ and login with the username admin and the
|
23
|
+
password pass@word1
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
$:.unshift "./lib"
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'sinatra-s3'
|
6
|
+
require 'sinatra-s3/tasks'
|
7
|
+
|
8
|
+
spec = Gem::Specification.new do |s|
|
9
|
+
s.name = "sinatra-s3"
|
10
|
+
s.version = S3::VERSION
|
11
|
+
s.author = "David Ricciardi"
|
12
|
+
s.email = "nricciar@gmail.com"
|
13
|
+
s.homepage = "http://github.com/nricciar/sinatra-s3"
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.summary = "An implementation of the Amazon S3 API in Ruby"
|
16
|
+
s.files = FileList["{bin,lib,public,examples}/**/*"].to_a +
|
17
|
+
FileList["db/migrate/*"].to_a +
|
18
|
+
["Rakefile","s3.yml.example"]
|
19
|
+
s.require_path = "lib"
|
20
|
+
s.executables = ['sinatra-s3']
|
21
|
+
s.test_files = FileList["{test}/*.rb"].to_a
|
22
|
+
s.has_rdoc = false
|
23
|
+
s.extra_rdoc_files = ["README"]
|
24
|
+
s.add_dependency("sinatra", ">= 1.0")
|
25
|
+
s.add_dependency("aws-s3", ">= 0.6.2")
|
26
|
+
s.add_dependency("haml", ">= 2.2.15")
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
30
|
+
pkg.need_tar = true
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace :test do
|
34
|
+
find_file = lambda do |name|
|
35
|
+
file_name = lambda {|path| File.join(path, "#{name}.rb")}
|
36
|
+
root = $:.detect do |path|
|
37
|
+
File.exist?(file_name[path])
|
38
|
+
end
|
39
|
+
file_name[root] if root
|
40
|
+
end
|
41
|
+
|
42
|
+
TEST_LOADER = find_file['rake/rake_test_loader']
|
43
|
+
multiruby = lambda do |glob|
|
44
|
+
system 'multiruby', TEST_LOADER, *Dir.glob(glob)
|
45
|
+
end
|
46
|
+
|
47
|
+
Rake::TestTask.new(:all) do |test|
|
48
|
+
test.pattern = 'test/**/*_test.rb'
|
49
|
+
test.verbose = true
|
50
|
+
end
|
51
|
+
end
|
data/bin/sinatra-s3
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'sinatra-s3'
|
4
|
+
|
5
|
+
if ARGV.any? { |arg| %w(--version -v).any? { |flag| arg == flag } }
|
6
|
+
puts "Sinatra-S3 #{S3::VERSION}"
|
7
|
+
exit 0
|
8
|
+
end
|
9
|
+
|
10
|
+
app_path = ARGV.last
|
11
|
+
install_success = false
|
12
|
+
|
13
|
+
unless File.exists?(app_path)
|
14
|
+
FileUtils.mkdir_p(app_path)
|
15
|
+
|
16
|
+
config_ru = "require 'rubygems'\nrequire 'sinatra-s3'"
|
17
|
+
if ARGV.any? { |arg| %w(--include-wiki --wiki).any? { |flag| arg == flag } }
|
18
|
+
FileUtils.copy(File.join(S3::ROOT_DIR,"examples","wiki.rb"), File.join(app_path,"wiki.rb"))
|
19
|
+
config_ru += "\nrequire 'wiki'"
|
20
|
+
end
|
21
|
+
config_ru += "\n\nuse S3::Tracker if defined?(RubyTorrent)\nuse S3::Admin\nrun S3::Application"
|
22
|
+
File.open(File.join(app_path,"config.ru"),"w") { |f| f.write(config_ru) }
|
23
|
+
|
24
|
+
File.open(File.join(app_path,"Rakefile"),"w") { |f| f.write("require 'sinatra-s3/tasks'") }
|
25
|
+
FileUtils.copy(File.join(S3::ROOT_DIR,"s3.yml.example"), File.join(app_path,"s3.yml"))
|
26
|
+
|
27
|
+
puts "Sinatra-S3 installed in #{app_path}."
|
28
|
+
else
|
29
|
+
puts "Unable to install Sinatra-S3. Install dir already exists."
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class CreateBits < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :bits do |t|
|
5
|
+
t.column :id, :integer, :null => false
|
6
|
+
t.column :owner_id, :integer
|
7
|
+
t.column :parent_id, :integer
|
8
|
+
t.column :lft, :integer
|
9
|
+
t.column :rgt, :integer
|
10
|
+
t.column :type, :string, :limit => 6
|
11
|
+
t.column :name, :string, :limit => 255
|
12
|
+
t.column :created_at, :timestamp
|
13
|
+
t.column :updated_at, :timestamp
|
14
|
+
t.column :access, :integer
|
15
|
+
t.column :meta, :text
|
16
|
+
t.column :obj, :text
|
17
|
+
t.column :size, :integer, :default => 0
|
18
|
+
t.column :version, :string
|
19
|
+
t.column :deleted, :integer, :default => 0
|
20
|
+
end
|
21
|
+
add_index :bits, :name
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table :bits
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreateUsers < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :users do |t|
|
5
|
+
t.column :id, :integer, :null => false
|
6
|
+
t.column :login, :string, :limit => 40
|
7
|
+
t.column :password, :string, :limit => 40
|
8
|
+
t.column :email, :string, :limit => 64
|
9
|
+
t.column :key, :string, :limit => 64
|
10
|
+
t.column :secret, :string, :limit => 64
|
11
|
+
t.column :created_at, :datetime
|
12
|
+
t.column :updated_at, :timestamp
|
13
|
+
t.column :activated_at, :datetime
|
14
|
+
t.column :superuser, :integer, :default => 0
|
15
|
+
t.column :deleted, :integer, :default => 0
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
drop_table :users
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateBitsUsers < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :bits_users do |t|
|
5
|
+
t.column :bit_id, :integer
|
6
|
+
t.column :user_id, :integer
|
7
|
+
t.column :access, :integer
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
drop_table :bits_users
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class CreateTorrents < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :torrents do |t|
|
5
|
+
t.column :id, :integer, :null => false
|
6
|
+
t.column :bit_id, :integer
|
7
|
+
t.column :info_hash, :string, :limit => 40
|
8
|
+
t.column :metainfo, :binary
|
9
|
+
t.column :seeders, :integer, :null => false, :default => 0
|
10
|
+
t.column :leechers, :integer, :null => false, :default => 0
|
11
|
+
t.column :hits, :integer, :null => false, :default => 0
|
12
|
+
t.column :total, :integer, :null => false, :default => 0
|
13
|
+
t.column :updated_at, :timestamp
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
drop_table :torrents
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CreateTorrentPeers < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :torrent_peers do |t|
|
5
|
+
t.column :id, :integer, :null => false
|
6
|
+
t.column :torrent_id, :integer
|
7
|
+
t.column :guid, :string, :limit => 40
|
8
|
+
t.column :ipaddr, :string
|
9
|
+
t.column :port, :integer
|
10
|
+
t.column :uploaded, :integer, :null => false, :default => 0
|
11
|
+
t.column :downloaded, :integer, :null => false, :default => 0
|
12
|
+
t.column :remaining, :integer, :null => false, :default => 0
|
13
|
+
t.column :compact, :integer, :null => false, :default => 0
|
14
|
+
t.column :event, :integer, :null => false, :default => 0
|
15
|
+
t.column :key, :string, :limit => 55
|
16
|
+
t.column :created_at, :timestamp
|
17
|
+
t.column :updated_at, :timestamp
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.down
|
22
|
+
drop_table :torrent_peers
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
data/examples/README
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
To use the example wiki application insure you first have the wikicloth and ruby-git
|
2
|
+
gems installed, and you have followed all the Sinatra-S3 install instructions. Once
|
3
|
+
you have Sinatra-S3 running correctly run the following commands in the Sinatra-S3
|
4
|
+
root directory.
|
5
|
+
|
6
|
+
rake setup:wiki
|
7
|
+
rackup examples/wiki.ru -p 6060
|
8
|
+
|
9
|
+
Access your Wiki at http://localhost:6060/ and admin at http://localhost:6060/control/
|
data/examples/wiki.rb
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'sinatra-s3'
|
2
|
+
require 'wikicloth'
|
3
|
+
|
4
|
+
S3::Application.callback :mime_type => 'text/wiki' do
|
5
|
+
headers["Content-Type"] = "text/html"
|
6
|
+
if params.has_key?('edit')
|
7
|
+
r :edit, "Editing #{@slot.name.gsub(/_/,' ')}"
|
8
|
+
elsif params.has_key?('diff')
|
9
|
+
@from = Bit.find_by_version(params[:diff])
|
10
|
+
@to = Bit.find_by_version(params[:to])
|
11
|
+
@diff = @from.diff(@to)
|
12
|
+
r :diff, "Changes to #{@slot.name.gsub(/_/,' ')}"
|
13
|
+
elsif params.has_key?('history')
|
14
|
+
@history = Slot.find(:all, :conditions => [ 'name = ? AND parent_id = ?', @slot.name, @slot.parent_id ], :order => "id DESC", :limit => 20)
|
15
|
+
r :history, "Revision history for #{@slot.name.gsub(/_/,' ')}"
|
16
|
+
else
|
17
|
+
p = {}
|
18
|
+
headers.each { |k,v| p[$1.upcase.gsub(/\-/,'_')] = v if k =~ /x-amz-(.*)/ }
|
19
|
+
@wiki = WikiCloth::WikiCloth.new({
|
20
|
+
:data => response.body.respond_to?(:read) ? response.body.read : response.body.to_s,
|
21
|
+
:link_handler => CustomLinkHandler.new,
|
22
|
+
:params => p
|
23
|
+
})
|
24
|
+
r :wiki, @slot.name.gsub(/_/,' ')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
S3::Application.callback :error => 'NoSuchKey' do
|
29
|
+
headers["Content-Type"] = "text/html"
|
30
|
+
if params.has_key?('edit')
|
31
|
+
r :edit, "Edit Page"
|
32
|
+
else
|
33
|
+
r :does_not_exist, "Page Does Not Exist"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
S3::Application.callback :error => 'AccessDenied' do
|
38
|
+
if env['PATH_INFO'].nil? || env['PATH_INFO'] == '/'
|
39
|
+
redirect '/wiki/Main_Page'
|
40
|
+
else
|
41
|
+
status 401
|
42
|
+
headers["WWW-Authenticate"] = %(Basic realm="wiki")
|
43
|
+
headers["Content-Type"] = "text/html"
|
44
|
+
r :access_denied, "Access Denied"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
S3::Application.callback :when => 'before' do
|
49
|
+
#fix some caching issues
|
50
|
+
if params.has_key?('edit') || params.has_key?('history') || params.has_key?('diff')
|
51
|
+
env.delete('HTTP_IF_MODIFIED_SINCE')
|
52
|
+
env.delete('HTTP_IF_NONE_MATCH')
|
53
|
+
end
|
54
|
+
|
55
|
+
auth = Rack::Auth::Basic::Request.new(env)
|
56
|
+
next unless auth.provided? && auth.basic?
|
57
|
+
|
58
|
+
user = User.find_by_login(auth.credentials[0])
|
59
|
+
next if user.nil?
|
60
|
+
|
61
|
+
# Convert a valid basic authorization into a proper S3 AWS
|
62
|
+
# Authorization header
|
63
|
+
if user.password == hmac_sha1( auth.credentials[1], user.secret )
|
64
|
+
uri = env['PATH_INFO']
|
65
|
+
uri += "?" + env['QUERY_STRING'] if S3::RESOURCE_TYPES.include?(env['QUERY_STRING'])
|
66
|
+
canonical = [env['REQUEST_METHOD'], env['HTTP_CONTENT_MD5'], env['CONTENT_TYPE'],
|
67
|
+
(env['HTTP_X_AMZ_DATE'] || env['HTTP_DATE']), uri]
|
68
|
+
env['HTTP_AUTHORIZATION'] = "AWS #{user.key}:" + hmac_sha1(user.secret, canonical.map{|v|v.to_s.strip} * "\n")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class CustomLinkHandler < WikiCloth::WikiLinkHandler
|
73
|
+
def url_for(page)
|
74
|
+
page = page.strip.gsub(/\s+/,'_')
|
75
|
+
page = "/#{$1.downcase}/#{$2}" if page =~ /^([A-Za-z]+):(.*)$/
|
76
|
+
page
|
77
|
+
end
|
78
|
+
|
79
|
+
def link_attributes_for(page)
|
80
|
+
{ :href => url_for(page) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def external_link(url,text)
|
84
|
+
self.external_links << url
|
85
|
+
elem.a({ :href => url, :target => "_blank", :class => "exlink" }) { |x| x << (text.blank? ? url : text) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def include_resource(resource,options=[])
|
89
|
+
if params[resource].nil?
|
90
|
+
begin
|
91
|
+
bucket = Bucket.find_root('templates')
|
92
|
+
slot = bucket.find_slot(resource)
|
93
|
+
unless slot.nil?
|
94
|
+
file = open(File.join(S3::STORAGE_PATH, slot.obj.path))
|
95
|
+
wiki_page = WikiCloth::WikiCloth.new({
|
96
|
+
:data => file.instance_of?(File) ? file.read : file.to_s,
|
97
|
+
:link_handler => self,
|
98
|
+
:params => params
|
99
|
+
})
|
100
|
+
return wiki_page.to_html
|
101
|
+
end
|
102
|
+
rescue S3::NoSuchKey
|
103
|
+
puts "Unknown resource #{resource}"
|
104
|
+
end
|
105
|
+
else
|
106
|
+
return params[resource]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class S3::Application < Sinatra::Base; enable :inline_templates; end
|
112
|
+
|
113
|
+
__END__
|
114
|
+
|
115
|
+
@@ layout
|
116
|
+
%html
|
117
|
+
%head
|
118
|
+
%title #{@title}
|
119
|
+
%style{:type => "text/css"}
|
120
|
+
@import '/control/s/css/control.css';
|
121
|
+
%style{:type => "text/css"}
|
122
|
+
@import '/control/s/css/wiki.css';
|
123
|
+
%body
|
124
|
+
%div#header
|
125
|
+
%h1
|
126
|
+
%a{:href => "/"} Wiki on Sinatra-S3
|
127
|
+
%div#page
|
128
|
+
- if status < 300
|
129
|
+
%div.menu
|
130
|
+
%ul
|
131
|
+
%li
|
132
|
+
%a{ :href => "#{env['PATH_INFO']}", :class => (!params.has_key?('diff') && !params.has_key?('history') && !params.has_key?('edit') ? "active" : "") } Content
|
133
|
+
%li
|
134
|
+
%a{ :href => "#{env['PATH_INFO']}?edit", :class => (params.has_key?('edit') ? "active" : "") } Edit
|
135
|
+
- if defined?(Git)
|
136
|
+
%li
|
137
|
+
%a{ :href => "#{env['PATH_INFO']}?history", :class => (params.has_key?('history') || params.has_key?('diff') ? "active" : "") } History
|
138
|
+
%h1 #{env['PATH_INFO'] =~ /\/([^\/]+)$/ ? "#{$1.gsub('_',' ')}" : "Sinatra-S3 Wiki"}
|
139
|
+
= yield
|
140
|
+
|
141
|
+
@@ access_denied
|
142
|
+
%h2 Access Denied
|
143
|
+
%p You are not authorized to access the specified resource.
|
144
|
+
|
145
|
+
@@ diff
|
146
|
+
%div#content
|
147
|
+
%p Change Summary: #{@diff.stats[:total][:insertions]} insertions and #{@diff.stats[:total][:deletions]} deletions
|
148
|
+
- @lines = @diff.patch.gsub('<','<').gsub('>','>').split("\n")
|
149
|
+
- @lines[4..-1].each do |line|
|
150
|
+
- case
|
151
|
+
- when line =~ /\-([0-9]+)(,([0-9]+)|) \+([0-9]+),([0-9]+)/
|
152
|
+
%div{ :style => "font-weight:bold;padding:5px 0" } Line #{$1}
|
153
|
+
- when line[0,1] == "\\"
|
154
|
+
- when line[0,1] == "+"
|
155
|
+
%ins{ :style => "background-color:#99ff99" } #{line[1,line.length]}
|
156
|
+
- when line[0,1] == "-"
|
157
|
+
%del{ :style => "background-color:#ff9999" } #{line[1,line.length]}
|
158
|
+
- else
|
159
|
+
%div{ :style => "background-color:#ebebeb" } #{line}
|
160
|
+
|
161
|
+
@@ does_not_exist
|
162
|
+
%h2 Page Does Not Exist
|
163
|
+
%p
|
164
|
+
The page you were trying to access does not exist. Perhaps you would like to
|
165
|
+
%a{ :href => "#{env['PATH_INFO']}?edit" } create it
|
166
|
+
?
|
167
|
+
|
168
|
+
@@ edit
|
169
|
+
%h2 #{@slot.nil? ? "Edit Page" : "Editing #{@slot.name.gsub(/_/,' ')}"}
|
170
|
+
%form.create{ :method => "POST", :action => env['PATH_INFO'] }
|
171
|
+
%input{ :type => "hidden", :name => "redirect", :value => env['PATH_INFO'] }
|
172
|
+
%input{ :type => "hidden", :name => "Content-Type", :value => "text/wiki" }
|
173
|
+
%div.required
|
174
|
+
- page_contents = status >= 300 ? "" : (response.body.respond_to?(:read) ? response.body.read : response.body.to_s)
|
175
|
+
%label{ :for => "page_contents" } Contents
|
176
|
+
%textarea{ :name => "file", :id => "page_contents", :style => "width:100%;height:20em" } #{page_contents}
|
177
|
+
%div.required
|
178
|
+
%label{ :for => "page_comment" } Comment:
|
179
|
+
%input{ :type => "text", :name => "x-amz-meta-comment", :id => "page_comment" }
|
180
|
+
%input{ :type => "submit", :value => "Update" }
|
181
|
+
|
182
|
+
@@ history
|
183
|
+
%h2 Revision history of #{@slot.name.gsub(/_/,' ')}
|
184
|
+
%form{ :action => env['PATH_INFO'], :method => "GET" }
|
185
|
+
%table#revision_history
|
186
|
+
- @history.each_with_index do |rev, count|
|
187
|
+
%tr
|
188
|
+
%td.check
|
189
|
+
%input{ :type => "radio", :name => "diff", :value => rev.version }
|
190
|
+
%td.check
|
191
|
+
%input{ :type => "radio", :name => "to", :value => rev.version }
|
192
|
+
%td
|
193
|
+
%a{ :href => "#{env['PATH_INFO']}?version-id=#{rev.version}" } #{rev.meta['comment']}
|
194
|
+
on #{rev.updated_at}
|
195
|
+
%input{ :type => "submit", :value => "Compare Revisions" }
|
196
|
+
|
197
|
+
@@ wiki
|
198
|
+
%div#wiki_page
|
199
|
+
= preserve @wiki.to_html
|
data/examples/wiki.ru
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009.
|
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.
|
@@ -0,0 +1,81 @@
|
|
1
|
+
Ruby implementation of the MediaWiki markup language.
|
2
|
+
|
3
|
+
Supports
|
4
|
+
---------------------------------------------------
|
5
|
+
|
6
|
+
* Variables, Templates {{ ... }}
|
7
|
+
* Links
|
8
|
+
o External Links [ ... ]
|
9
|
+
o Internal Links, Images [[ ... ]]
|
10
|
+
+ (see also pipe trick)
|
11
|
+
* Wikimedia Markup
|
12
|
+
o == Headings ==
|
13
|
+
o Lists (*#;:)
|
14
|
+
o bold ('''), italic ('') or both (''''')
|
15
|
+
o Horizontal rule (----)
|
16
|
+
o Tables
|
17
|
+
* <code>,<nowiki>,<pre> (disable wiki markup)
|
18
|
+
o space at the beginning of a line (<pre>)
|
19
|
+
* <ref> and <references/> support
|
20
|
+
* html sanitization
|
21
|
+
|
22
|
+
Install
|
23
|
+
---------------------------------------------------
|
24
|
+
|
25
|
+
git clone git://github.com/nricciar/wikicloth.git
|
26
|
+
cd wikicloth/
|
27
|
+
gem build wikicloth.gemspec
|
28
|
+
sudo gem install wikicloth-0.1.3.gem
|
29
|
+
|
30
|
+
Usage
|
31
|
+
---------------------------------------------------
|
32
|
+
|
33
|
+
include WikiCloth
|
34
|
+
|
35
|
+
@wiki = WikiCloth.new({
|
36
|
+
:data => "<nowiki>{{test}}</nowiki> ''Hello {{test}}!''\n",
|
37
|
+
:params => { "test" => "World" } })
|
38
|
+
@wiki.to_html => "<p>{{test}} <i>Hello World!</i></p>"
|
39
|
+
|
40
|
+
|
41
|
+
Wiki Links and Variable/Template Handling
|
42
|
+
---------------------------------------------------
|
43
|
+
|
44
|
+
Use the url_for and link_attributes_for methods to override the default URL for
|
45
|
+
an [[internal link]]. If you need even more control, the link_for can also be
|
46
|
+
used to return raw html.
|
47
|
+
|
48
|
+
class CustomLinkHandler < WikiCloth::WikiLinkHandler
|
49
|
+
|
50
|
+
def url_for(page)
|
51
|
+
"javascript:alert('You clicked on: #{page}');"
|
52
|
+
end
|
53
|
+
|
54
|
+
def link_attributes_for(page)
|
55
|
+
{ :href => url_for(page) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def include_resource(resource,options=[])
|
59
|
+
case resource
|
60
|
+
when "date"
|
61
|
+
Time.now.to_s
|
62
|
+
else
|
63
|
+
# default behavior
|
64
|
+
super(resource,options)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
@wiki = WikiCloth::WikiCloth.new({
|
72
|
+
:params => { "PAGENAME" => "Testing123" },
|
73
|
+
:link_handler => CustomLinkHandler.new,
|
74
|
+
:data => "Hello World From {{ PAGENAME }} on {{ date }}\n"
|
75
|
+
})
|
76
|
+
|
77
|
+
@wiki.to_html =>
|
78
|
+
<p>
|
79
|
+
<a href="javascript:alert('You clicked on: Hello World');">Hello World</a> From Testing123 on Wed Jul 08 22:23:44 -0400 2009
|
80
|
+
</p>
|
81
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the wikicloth plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the wikicloth plugin.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'WikiCloth'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "lib", "wikicloth")
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ExtendedString
|
2
|
+
|
3
|
+
def blank?
|
4
|
+
respond_to?(:empty?) ? empty? : !self
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_slug
|
8
|
+
self.gsub(/\W+/, '-').gsub(/^-+/,'').gsub(/-+$/,'').downcase
|
9
|
+
end
|
10
|
+
|
11
|
+
def auto_link
|
12
|
+
url_check = Regexp.new( '(^|[\n ])([\w]+?://[\w]+[^ \"\r\n\t<]*)', Regexp::MULTILINE | Regexp::IGNORECASE )
|
13
|
+
www_check = Regexp.new( '(^|[\n ])((www)\.[^ \"\t\n\r<]*)', Regexp::MULTILINE | Regexp::IGNORECASE )
|
14
|
+
self.gsub!(url_check, '\1<a href="\2">\2</a>')
|
15
|
+
self.gsub!(www_check, '\1<a href="http://\2">\2</a>')
|
16
|
+
to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def dump()
|
20
|
+
ret = to_s
|
21
|
+
delete!(to_s)
|
22
|
+
ret
|
23
|
+
end
|
24
|
+
|
25
|
+
def smart_split(char)
|
26
|
+
ret = []
|
27
|
+
tmp = ""
|
28
|
+
inside = 0
|
29
|
+
to_s.each_char do |x|
|
30
|
+
if x == char && inside == 0
|
31
|
+
ret << tmp
|
32
|
+
tmp = ""
|
33
|
+
else
|
34
|
+
inside += 1 if x == "[" || x == "{" || x == "<"
|
35
|
+
inside -= 1 if x == "]" || x == "}" || x == ">"
|
36
|
+
tmp += x
|
37
|
+
end
|
38
|
+
end
|
39
|
+
ret << tmp unless tmp.empty?
|
40
|
+
ret
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|