ruby-mediawiki 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +674 -0
- data/README +60 -0
- data/apps/comment_sync.rb +178 -0
- data/apps/date_determinator.rb +185 -0
- data/apps/iso_639_leecher.rb +58 -0
- data/apps/localization_sync.rb +143 -0
- data/apps/rdoc_to_wiki.rb +126 -0
- data/apps/speed_metal_bot.rb +79 -0
- data/apps/wikicat.rb +30 -0
- data/apps/wikipost.rb +32 -0
- data/lib/mediawiki.rb +170 -0
- data/lib/mediawiki/article.rb +259 -0
- data/lib/mediawiki/category.rb +54 -0
- data/lib/mediawiki/dotfile.rb +51 -0
- data/lib/mediawiki/minibrowser.rb +140 -0
- data/lib/mediawiki/specialpage.rb +39 -0
- data/lib/mediawiki/table.rb +95 -0
- data/mediawikirc.sample +25 -0
- data/mkrdoc.sh +3 -0
- metadata +62 -0
data/README
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
Ruby-MediaWiki 0.1
|
2
|
+
------------------
|
3
|
+
------------------
|
4
|
+
|
5
|
+
A library to retrieve and modify content managed by the popular
|
6
|
+
MediaWiki software.
|
7
|
+
|
8
|
+
|
9
|
+
AUTHORS
|
10
|
+
=======
|
11
|
+
|
12
|
+
Sven Klemm
|
13
|
+
Stephan Maka
|
14
|
+
Mike Gerber
|
15
|
+
Michael Witrant
|
16
|
+
|
17
|
+
(patches go to stephan@spaceboyz.net)
|
18
|
+
|
19
|
+
|
20
|
+
LICENSE
|
21
|
+
=======
|
22
|
+
|
23
|
+
Distributed under the GNU General Public License version 3, see the
|
24
|
+
COPYING file.
|
25
|
+
|
26
|
+
|
27
|
+
USAGE
|
28
|
+
=====
|
29
|
+
|
30
|
+
Ruby-MediaWiki relies on a configuration file with URLs, user account
|
31
|
+
details and per-agent settings in YAML. The sample mediawikirc.sample
|
32
|
+
should be rather self-explanatory.
|
33
|
+
|
34
|
+
There are various environment variables for easy usage:
|
35
|
+
|
36
|
+
* MEDIAWIKI_RC - location of the configuration file
|
37
|
+
(default: ~/.mediawikirc)
|
38
|
+
* MEDIAWIKI_WIKI - which section of the configuration file to use
|
39
|
+
(default is the one set in the `default' key)
|
40
|
+
* MEDIAWIKI_DEBUG - if set, set the log level to DEBUG
|
41
|
+
|
42
|
+
Quick start:
|
43
|
+
------------
|
44
|
+
ruby-mediawiki % export RUBYLIB=`pwd`/lib
|
45
|
+
ruby-mediawiki % export MEDIAWIKI_RC=mediawikirc.sample
|
46
|
+
ruby-mediawiki % export MEDIAWIKI_WIKI=wpde
|
47
|
+
ruby-mediawiki % ruby apps/wikicat.rb Arschgeweih
|
48
|
+
|
49
|
+
|
50
|
+
RESOURCES
|
51
|
+
=========
|
52
|
+
|
53
|
+
German description:
|
54
|
+
https://wiki.c3d2.de/Ruby-MediaWiki
|
55
|
+
|
56
|
+
RDoc to Wiki:
|
57
|
+
https://wiki.c3d2.de/Ruby-MediaWiki/Documentation
|
58
|
+
|
59
|
+
SVN repository:
|
60
|
+
svn://svn.c3d2.de/ruby-mediawiki/trunk
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
=begin
|
3
|
+
This file is part of Ruby-MediaWiki.
|
4
|
+
|
5
|
+
Ruby-MediaWiki is free software: you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License as
|
7
|
+
published by the Free Software Foundation, either version 3 of the
|
8
|
+
License, or (at your option) any later version.
|
9
|
+
|
10
|
+
Ruby-MediaWiki is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with Ruby-MediaWiki. If not, see
|
17
|
+
<http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
$:.unshift('../lib')
|
21
|
+
require 'postgres'
|
22
|
+
require 'yaml'
|
23
|
+
require 'mediawiki'
|
24
|
+
require 'mediawiki/dotfile'
|
25
|
+
require 'mediawiki/table'
|
26
|
+
|
27
|
+
class SQL_Parser
|
28
|
+
# returns a hash with the tablename as key
|
29
|
+
def self.parse( sql )
|
30
|
+
tables = {}
|
31
|
+
current = nil
|
32
|
+
sql.each_line do | line |
|
33
|
+
line.gsub!(/,$/, '')
|
34
|
+
next if line.match(/^ *$/) or line.match(/BEGIN/) or line.match(/COMMIT/)
|
35
|
+
if match = line.match(/CREATE TABLE ([a-z_]+) *\(/)
|
36
|
+
current = match[1]
|
37
|
+
tables[match[1]] = {:field_names => [], :field => {}}
|
38
|
+
elsif line.match(/\) *(WITHOUT OIDS)?;/)
|
39
|
+
current = nil
|
40
|
+
elsif current
|
41
|
+
if match = line.match(/^ +([a-z_0-9]+) +(.*)$/)
|
42
|
+
tables[current][:field_names].push( match[1] )
|
43
|
+
tables[current][:field][match[1]] = match[2].gsub(/(NOT NULL|UNIQUE|DEFAULT|CHECK).*/, '')
|
44
|
+
elsif match = line.match(/^ *(FOREIGN KEY|PRIMARY KEY|CHECK|UNIQUE)/)
|
45
|
+
else
|
46
|
+
puts "unparsed line: #{line}"
|
47
|
+
end
|
48
|
+
else
|
49
|
+
puts "unrecognized line: #{line.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
tables
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# reads and writes comment to/from the database
|
57
|
+
class SQL_Comments
|
58
|
+
|
59
|
+
# setup database connection
|
60
|
+
def initialize( config )
|
61
|
+
@connection = PGconn.connect( config['host'], config['port'], nil, nil, config['database'], config['username'], config['password'])
|
62
|
+
end
|
63
|
+
|
64
|
+
def escape( data )
|
65
|
+
data.gsub("\\",'').gsub("'", "''")
|
66
|
+
end
|
67
|
+
|
68
|
+
def escape_ident( data )
|
69
|
+
data.gsub("\\",'').gsub('"', '')
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_table_description( table )
|
73
|
+
@connection.exec("SELECT description
|
74
|
+
FROM pg_description
|
75
|
+
INNER JOIN pg_class ON ( pg_class.oid = pg_description.objoid )
|
76
|
+
WHERE pg_description.objsubid = 0 AND
|
77
|
+
pg_class.relname = '#{escape(table)}';"
|
78
|
+
).entries.flatten[0]
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_table_description( table, text )
|
82
|
+
@connection.exec("COMMENT ON TABLE \"#{escape_ident(table)}\" IS #{text.to_s == "" ? 'NULL' : "'#{escape(text.strip)}'"};")
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_column_description( table, column, text )
|
86
|
+
@connection.exec("COMMENT ON COLUMN \"#{escape_ident(table)}\".\"#{escape_ident(column)}\" IS #{text.to_s == "" ? 'NULL' : "'#{escape(text.strip)}'"};")
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_column_description( table, column )
|
90
|
+
@connection.exec("SELECT description
|
91
|
+
FROM pg_description
|
92
|
+
INNER JOIN pg_class ON ( pg_class.oid = pg_description.objoid )
|
93
|
+
INNER JOIN pg_attribute ON
|
94
|
+
( pg_attribute.attrelid = pg_description.objoid AND
|
95
|
+
pg_description.objsubid = pg_attribute.attnum )
|
96
|
+
WHERE pg_class.relname = '#{escape(table)}' AND
|
97
|
+
pg_attribute.attname = '#{escape(column)}'"
|
98
|
+
).entries.flatten[0]
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
class Comment_Synchronizer
|
105
|
+
|
106
|
+
def initialize( wiki, config, sql)
|
107
|
+
@wiki = MediaWiki.dotfile
|
108
|
+
@sql = SQL_Comments.new(config)
|
109
|
+
@tables = SQL_Parser.parse( sql )
|
110
|
+
end
|
111
|
+
|
112
|
+
# update wiki with content from database
|
113
|
+
def update_wiki
|
114
|
+
# generate index page
|
115
|
+
page = @wiki.article('Database/Tables')
|
116
|
+
page.text = "This is a list of all tables used in pentabarf\n\n"
|
117
|
+
@tables.keys.sort.each do | table |
|
118
|
+
page.text += "*[[Database/Tables/#{table.capitalize}|#{table}]]\n"
|
119
|
+
end
|
120
|
+
page.text += "[[Category:Database]]"
|
121
|
+
page.submit('generating list of tables')
|
122
|
+
|
123
|
+
# create one page for each table
|
124
|
+
@tables.keys.sort.each do | table |
|
125
|
+
page = @wiki.article("Database/Tables/#{table.capitalize}")
|
126
|
+
|
127
|
+
# create wiki page
|
128
|
+
page.text = @sql.get_table_description( table ).to_s + "\n"
|
129
|
+
# table header
|
130
|
+
page.text += "==Columns==\n"
|
131
|
+
page.text += "[[Database/Tables|<< List of Tables]]\n"
|
132
|
+
t = MediaWiki::Table.new
|
133
|
+
t.style = 'border="1" cellspacing="0" cellpadding="3" style="border-collapse: collapse;"'
|
134
|
+
t.header_style = 'bgcolor="lightblue"'
|
135
|
+
t.header = ['field name', 'datatype', 'description']
|
136
|
+
|
137
|
+
@tables[table][:field_names].each do | field_name |
|
138
|
+
t.data.push([field_name, @tables[table][:field][field_name], @sql.get_column_description( table, field_name)])
|
139
|
+
end
|
140
|
+
page.text += t.text
|
141
|
+
page.text += "\n[[Category:Database]]\n"
|
142
|
+
page.submit("updating page for table #{table}")
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# write documentation from wiki into database
|
148
|
+
def update_database
|
149
|
+
# fetch content from all wiki pages and put it in the database
|
150
|
+
@tables.keys.sort.each do | table |
|
151
|
+
|
152
|
+
# get the section containing the general description
|
153
|
+
page = @wiki.article("Database/Tables/#{table.capitalize}", 0)
|
154
|
+
@sql.set_table_description( table, page.text )
|
155
|
+
|
156
|
+
# get the section containing the column table
|
157
|
+
page = @wiki.article("Database/Tables/#{table.capitalize}", 1)
|
158
|
+
state = :description
|
159
|
+
column = ''
|
160
|
+
# parse wiki text
|
161
|
+
MediaWiki::Table.parse( page.text ).each do | column |
|
162
|
+
next if column[0] == 'field name' # this is the header column
|
163
|
+
@sql.set_column_description( table, column[0], column[2] )
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
db_config = YAML.load_file('db_config.yml')['development']
|
172
|
+
#db_config = {'host' => 'localhost', 'port' => 5432, 'database' => 'pentabarf', 'username' => 'joe', 'password' => 'secret'}
|
173
|
+
sql = `svnlook cat /var/subversion/pentabarf /trunk/sql/tables.sql`
|
174
|
+
|
175
|
+
bot = Comment_Synchronizer.new( :pentabarf, db_config, sql )
|
176
|
+
bot.update_database
|
177
|
+
bot.update_wiki
|
178
|
+
|
@@ -0,0 +1,185 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
=begin
|
3
|
+
This file is part of Ruby-MediaWiki.
|
4
|
+
|
5
|
+
Ruby-MediaWiki is free software: you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License as
|
7
|
+
published by the Free Software Foundation, either version 3 of the
|
8
|
+
License, or (at your option) any later version.
|
9
|
+
|
10
|
+
Ruby-MediaWiki is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with Ruby-MediaWiki. If not, see
|
17
|
+
<http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
require 'yaml'
|
21
|
+
$:.unshift('../lib')
|
22
|
+
require 'mediawiki/dotfile'
|
23
|
+
|
24
|
+
include MediaWiki
|
25
|
+
|
26
|
+
class DateUser
|
27
|
+
attr_reader :name
|
28
|
+
|
29
|
+
def initialize(name, hsh)
|
30
|
+
@name = name
|
31
|
+
@hsh = hsh
|
32
|
+
end
|
33
|
+
|
34
|
+
def dates
|
35
|
+
@hsh.keys
|
36
|
+
end
|
37
|
+
|
38
|
+
def day(d)
|
39
|
+
@hsh[d]
|
40
|
+
end
|
41
|
+
|
42
|
+
def day_class(d)
|
43
|
+
if day(d) == nil
|
44
|
+
nil
|
45
|
+
elsif day(d) =~ /^[yj]/i
|
46
|
+
true
|
47
|
+
elsif day(d) =~ /^n/i
|
48
|
+
false
|
49
|
+
else
|
50
|
+
""
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def day_style(d)
|
55
|
+
case day_class(d)
|
56
|
+
when nil then ""
|
57
|
+
when true then 'bgcolor="#7fff7f"'
|
58
|
+
when false then 'bgcolor="#ff7f7f"'
|
59
|
+
else 'bgcolor="#bfbfbf"'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class DateData
|
65
|
+
def initialize(yaml)
|
66
|
+
@users = []
|
67
|
+
@error = nil
|
68
|
+
begin
|
69
|
+
YAML::load(yaml).each { |user,dates|
|
70
|
+
@users << DateUser.new(user, dates)
|
71
|
+
}
|
72
|
+
rescue Exception => e
|
73
|
+
puts "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
74
|
+
@error = e.to_s
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def table
|
79
|
+
return @error if @error
|
80
|
+
|
81
|
+
s = ''
|
82
|
+
|
83
|
+
##
|
84
|
+
# Collect dates
|
85
|
+
##
|
86
|
+
dates = []
|
87
|
+
dates_yes = {}
|
88
|
+
@users.each { |user| dates += user.dates }
|
89
|
+
|
90
|
+
##
|
91
|
+
# Sort dates
|
92
|
+
##
|
93
|
+
dates.uniq!
|
94
|
+
dates.sort! { |a,b|
|
95
|
+
if a =~ /^(\d+)\.(\d+)\./
|
96
|
+
a_day = $1
|
97
|
+
a_month = $2
|
98
|
+
if b =~ /^(\d+)\.(\d+)\./
|
99
|
+
b_day = $1
|
100
|
+
b_month = $2
|
101
|
+
if a_month.to_i == b_month.to_i
|
102
|
+
a_day.to_i <=> b_day.to_i
|
103
|
+
else
|
104
|
+
a_month.to_i <=> b_month.to_i
|
105
|
+
end
|
106
|
+
else
|
107
|
+
a <=> b
|
108
|
+
end
|
109
|
+
else
|
110
|
+
a <=> b
|
111
|
+
end
|
112
|
+
}
|
113
|
+
|
114
|
+
##
|
115
|
+
# Construct header
|
116
|
+
##
|
117
|
+
s += "{| border=\"1\" cellpadding=\"2\" cellspacing=\"0\" style=\"border-collapse:collapse;\"\n|-\n! \n"
|
118
|
+
dates.each { |date|
|
119
|
+
s += "!#{date}\n"
|
120
|
+
dates_yes[date] = 0
|
121
|
+
}
|
122
|
+
|
123
|
+
##
|
124
|
+
# Construct rows
|
125
|
+
##
|
126
|
+
@users.each { |user|
|
127
|
+
s += "|-\n|[[User:#{user.name}|#{user.name}]]\n"
|
128
|
+
dates.each { |date|
|
129
|
+
s += "| #{user.day_style(date)} | #{user.day(date)}\n"
|
130
|
+
dates_yes[date] += 1 if user.day_class(date) == true
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
##
|
135
|
+
# Build summary
|
136
|
+
##
|
137
|
+
s += "|-\n|'''sum(ja)'''\n"
|
138
|
+
dates.each { |date|
|
139
|
+
s += "|'''#{dates_yes[date]}'''\n"
|
140
|
+
}
|
141
|
+
s += "|}"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
wiki, conf = MediaWiki.dotfile('date determinator')
|
148
|
+
conf['pages'].each { |name|
|
149
|
+
page = wiki.article(name)
|
150
|
+
|
151
|
+
datasets = {}
|
152
|
+
current_data_name = nil
|
153
|
+
current_data_yaml = ''
|
154
|
+
page.text.split(/\n/).each { |line|
|
155
|
+
if line =~ /BEGIN DATA "(.+?)"/
|
156
|
+
current_data_name = $1
|
157
|
+
current_data_yaml = ''
|
158
|
+
elsif line =~ /END DATA/ and current_data_name
|
159
|
+
datasets[current_data_name] = DateData.new(current_data_yaml)
|
160
|
+
current_data_name = nil
|
161
|
+
current_data_yaml = ''
|
162
|
+
elsif current_data_name
|
163
|
+
current_data_yaml += "#{line}\n"
|
164
|
+
end
|
165
|
+
}
|
166
|
+
|
167
|
+
|
168
|
+
text_old = page.text.dup
|
169
|
+
|
170
|
+
signature = /(<!-- BEGIN TABLE ")(.+?)(" -->)(.+?)(<!-- END TABLE -->)/m
|
171
|
+
page.text.gsub!(signature) { |part|
|
172
|
+
begin1,name,begin2,obsolete,end1 = part.match(signature).to_a[1..-1]
|
173
|
+
table = datasets[name] ? datasets[name].table : "DATA #{name} not found!"
|
174
|
+
p table
|
175
|
+
"#{begin1}#{name}#{begin2}\n#{table}\n#{end1}"
|
176
|
+
}
|
177
|
+
puts page.text
|
178
|
+
|
179
|
+
if page.text != text_old
|
180
|
+
puts "submitting"
|
181
|
+
page.submit('Date Determinator run')
|
182
|
+
end
|
183
|
+
|
184
|
+
puts "done"
|
185
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
=begin
|
3
|
+
This file is part of Ruby-MediaWiki.
|
4
|
+
|
5
|
+
Ruby-MediaWiki is free software: you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License as
|
7
|
+
published by the Free Software Foundation, either version 3 of the
|
8
|
+
License, or (at your option) any later version.
|
9
|
+
|
10
|
+
Ruby-MediaWiki is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with Ruby-MediaWiki. If not, see
|
17
|
+
<http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
$:.unshift('../lib')
|
21
|
+
|
22
|
+
require 'mediawiki/dotfile'
|
23
|
+
require 'mediawiki/table'
|
24
|
+
require 'momomoto/momomoto'
|
25
|
+
require 'momomoto/tables'
|
26
|
+
require 'momomoto/bot_login'
|
27
|
+
|
28
|
+
ENV['MEDIAWIKI_WIKI'] = 'wikipedia_de'
|
29
|
+
|
30
|
+
db_config = YAML.load_file('db_config.yml')['development']
|
31
|
+
Momomoto::Base.connect(db_config)
|
32
|
+
Momomoto::Bot_login.authorize('ui_tagger')
|
33
|
+
|
34
|
+
wiki = MediaWiki.dotfile
|
35
|
+
page = wiki.article('ISO 639', 3)
|
36
|
+
t = MediaWiki::Table.parse( page.text )
|
37
|
+
|
38
|
+
t.shift
|
39
|
+
|
40
|
+
t.each do | row |
|
41
|
+
row[2].split( '/' ).each do | iso_code |
|
42
|
+
id = Momomoto::Language.find({:iso_639_code=>iso_code})
|
43
|
+
next unless id.length == 1
|
44
|
+
match = row[0].match /\[\[(.*\|)?(.+)\]\]/
|
45
|
+
name = match[2]
|
46
|
+
|
47
|
+
local = Momomoto::Language_localized.find({:language_id=>id.language_id,:translated_id=>144})
|
48
|
+
if local.length == 0 && name != ''
|
49
|
+
local.create
|
50
|
+
local.language_id = id.language_id
|
51
|
+
local.translated_id = 144
|
52
|
+
local.name = name
|
53
|
+
local.write
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|