ruby-mediawiki 0.1

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.
@@ -0,0 +1,143 @@
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
+
21
+ # this bot expects a fully functional local pentabarf installation
22
+
23
+ $:.unshift('../lib')
24
+
25
+ require 'mediawiki/dotfile'
26
+ require 'mediawiki/table'
27
+ require 'momomoto/momomoto'
28
+ require 'momomoto/tables'
29
+ require 'momomoto/bot_login'
30
+
31
+ class Localization_Sync
32
+
33
+ def initialize
34
+ @wiki = MediaWiki.dotfile
35
+
36
+ db_config = YAML.load_file('db_config.yml')['development']
37
+ Momomoto::Base.connect(db_config)
38
+ Momomoto::Bot_login.authorize('ui_tagger')
39
+
40
+ @lang = {}
41
+ Momomoto::Language.find({:f_localized=>'t'},nil,"lower(tag)").each do | l | @lang[l.tag] = l.language_id end
42
+
43
+ @@syncable = [
44
+ ['Attachment_type', :attachment_type_id, :tag, Momomoto::Attachment_type, Momomoto::Attachment_type_localized],
45
+ ['Conference_phase', :conference_phase_id, :tag, Momomoto::Conference_phase, Momomoto::Conference_phase_localized],
46
+ ['Conflict', :conflict_id, :tag, Momomoto::Conflict, Momomoto::Conflict_localized],
47
+ ['Conflict_level', :conflict_level_id, :tag, Momomoto::Conflict_level, Momomoto::Conflict_level_localized],
48
+ ['Country', :country_id, :iso_3166_code, Momomoto::Country, Momomoto::Country_localized],
49
+ ['Currency', :currency_id, :iso_4217_code, Momomoto::Currency, Momomoto::Currency_localized],
50
+ ['Event_origin', :event_origin_id, :tag, Momomoto::Event_origin, Momomoto::Event_origin_localized],
51
+ ['Event_role', :event_role_id, :tag, Momomoto::Event_role, Momomoto::Event_role_localized],
52
+ ['Event_state', :event_state_id, :tag, Momomoto::Event_state, Momomoto::Event_state_localized],
53
+ ['Event_type', :event_type_id, :tag, Momomoto::Event_type, Momomoto::Event_type_localized],
54
+ ['Im_type', :im_type_id, :tag, Momomoto::Im_type, Momomoto::Im_type_localized],
55
+ ['Language', :language_id, :iso_639_code, Momomoto::Language, Momomoto::Language_localized, :translated_id],
56
+ ['Mime_type', :mime_type_id, :mime_type, Momomoto::Mime_type, Momomoto::Mime_type_localized],
57
+ ['Phone_type', :phone_type_id, :tag, Momomoto::Phone_type, Momomoto::Phone_type_localized],
58
+ ['Role', :role_id, :tag, Momomoto::Role, Momomoto::Role_localized],
59
+ ['Transport', :transport_id, :tag, Momomoto::Transport, Momomoto::Transport_localized],
60
+ ['Ui_message', :ui_message_id, :tag, Momomoto::Ui_message, Momomoto::Ui_message_localized]
61
+ ]
62
+
63
+ end
64
+
65
+ # creates wiki pages from the data in the database
66
+ def update_wiki
67
+ @@syncable.each do | row |
68
+ make_table( *row )
69
+ end
70
+ page = @wiki.article('Localization', 1)
71
+ page.text = "=Localizable Tables=\n"
72
+ @@syncable.each do | row |
73
+ page.text += "*[[Localization/#{row[0]}|#{row[0]}]]\n"
74
+ end
75
+ page.submit('updating localization page')
76
+ end
77
+
78
+ # reads wiki pages and updates the database according to the data in the wiki
79
+ def update_database
80
+ @@syncable.each do | row |
81
+ read_table( *row )
82
+ end
83
+ end
84
+
85
+ def read_table(table, tag_id, tag_name, tag_class, local_class, lang_id = :language_id)
86
+ page = @wiki.article("Localization/#{table}")
87
+ return if page.text == ''
88
+ t = MediaWiki::Table.parse( page.text )
89
+ header = t.shift
90
+ header.shift
91
+
92
+ local_class.new.begin
93
+
94
+ t.each do | row |
95
+ header.each_with_index do | lang_tag, index |
96
+ cur_tag = tag_class.find({tag_name=>row[0]})
97
+ next unless cur_tag.length == 1
98
+ cur_loc = local_class.find({lang_id=>@lang[header[index]],tag_id=>cur_tag[tag_id]})
99
+ next if row[index + 1] == ''
100
+ unless cur_loc.length == 1
101
+ cur_loc.create
102
+ cur_loc[lang_id] = @lang[header[index]]
103
+ cur_loc[tag_id] = cur_tag[tag_id]
104
+ end
105
+ cur_loc[:name] = row[index + 1].strip
106
+ cur_loc.write
107
+ end
108
+ end
109
+
110
+ local_class.new.commit
111
+
112
+ end
113
+
114
+ def make_table(table, tag_id, tag_name, tag_class, local_class, lang_id = :language_id)
115
+ tags = {}
116
+ tag_class.find().each do | tc | tags[tc[tag_name]] = tc[tag_id] end
117
+ local = local_class.find({lang_id=>@lang.values})
118
+
119
+ page = @wiki.article("Localization/#{table}")
120
+
121
+ t = MediaWiki::Table.new
122
+ t.style = 'border="1" cellspacing="0" cellpadding="3" style="border-collapse: collapse;"'
123
+ t.header_style = 'bgcolor="lightblue"'
124
+ t.header = ['']
125
+ @lang.each do | tag, id | t.header.push( tag ) end
126
+ tags.keys.sort.each do | tag |
127
+ row = [tag]
128
+ @lang.each do | key, language_id |
129
+ row.push(local.find_by_value({tag_id=>tags[tag],lang_id=>language_id}) ? local.name : '')
130
+ end
131
+ t.data.push( row )
132
+ end
133
+
134
+ page.text = "[[Localization|<< Localization]]\n" + t.text + "\n[[Category:Localization]]"
135
+ page.submit("updating localization pages")
136
+ end
137
+
138
+ end
139
+
140
+ s = Localization_Sync.new
141
+ s.update_database
142
+ s.update_wiki
143
+
@@ -0,0 +1,126 @@
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
+
21
+ require 'yaml'
22
+ require 'rdoc/ri/ri_reader'
23
+
24
+ $:.unshift('../lib')
25
+ require 'mediawiki/dotfile'
26
+
27
+
28
+ def find(dir, &block)
29
+ Dir.foreach(dir) { |file|
30
+ next if file =~ /^\./
31
+
32
+ path = "#{dir}/#{file}"
33
+ if File.directory?(path)
34
+ find(path) { |f| yield f }
35
+ else
36
+ yield path
37
+ end
38
+ }
39
+ end
40
+
41
+ def wiki_format(flow)
42
+ s = ''
43
+ case flow
44
+ when Array
45
+ flow.each { |subflow|
46
+ s += wiki_format(subflow)
47
+ }
48
+ when SM::Flow::LIST
49
+ flow.contents.each { |subflow|
50
+ s += wiki_format(subflow)
51
+ }
52
+ s += "\n"
53
+ when SM::Flow::LI
54
+ if flow.label =~ /:$/
55
+ s += "; #{flow.label}\n: #{flow.body}\n"
56
+ elsif flow.label =~ /^[ \*]$/
57
+ s += "#{flow.label} #{flow.body}\n"
58
+ else
59
+ s += "* '''#{flow.label}:''' #{flow.body}\n"
60
+ end
61
+ when SM::Flow::P
62
+ s += "#{flow.body}\n\n"
63
+ else
64
+ puts "Unknown Flow: #{flow.inspect}"
65
+ end
66
+ s.gsub!(/&quot;/, '"')
67
+ s.gsub!(/<b>(.+?)<\/b>/, '\'\'\'\1\'\'\'')
68
+ s.gsub!(/<i>(.+?)<\/i>/, '\'\'\1\'\'')
69
+ s.gsub!(/<tt>(.+?)<\/tt>/, '<em>\1</em>')
70
+ s
71
+ end
72
+
73
+
74
+ classes = []
75
+ methods = {}
76
+
77
+ find("../rdoc-ri") { |file|
78
+ next unless file =~ /\.yaml$/
79
+ ri = YAML::load(File.new(file))
80
+ case ri
81
+ when RI::ClassDescription
82
+ classes << ri
83
+ when RI::MethodDescription
84
+ methods[ri.full_name] = ri
85
+ else
86
+ puts "Unknown Description: #{ri.inspect}"
87
+ end
88
+ }
89
+
90
+ classes.sort! { |a,b|
91
+ a.full_name <=> b.full_name
92
+ }
93
+
94
+ text = ''
95
+ classes.each { |klass|
96
+ text += "==#{klass.full_name}==\n\n"
97
+ text += "Inherited from '''#{klass.superclass}'''\n\n" if klass.superclass
98
+ text += wiki_format(klass.comment || [])
99
+ klass.attributes.each { |attribute|
100
+ text += "===#{klass.full_name}##{attribute.name} (#{attribute.rw})===\n\n"
101
+ text += wiki_format(attribute.comment || [])
102
+ text += "\n"
103
+ }
104
+ klass.class_methods.each { |methodname|
105
+ method = methods["#{klass.full_name}::#{methodname.name}"]
106
+ text += "===#{method.full_name}#{method.params}===\n\n"
107
+ text += wiki_format(method.comment || [])
108
+ text += "\n"
109
+ }
110
+ klass.instance_methods.each { |methodname|
111
+ method = methods["#{klass.full_name}##{methodname.name}"]
112
+ text += "===#{method.full_name}#{method.params}===\n\n"
113
+ text += wiki_format(method.comment || [])
114
+ text += "\n"
115
+ }
116
+ }
117
+
118
+ if false # Dry run?
119
+ puts text
120
+ exit
121
+ end
122
+
123
+ wiki, conf = MediaWiki.dotfile('rdoc to wiki')
124
+ article = wiki.article(conf['page'])
125
+ article.text = "=#{conf['title']}=\n\n" + text
126
+ article.submit("I can even document myself :-)")
@@ -0,0 +1,79 @@
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
+
21
+ $:.unshift('../lib')
22
+ require 'mediawiki/dotfile'
23
+
24
+ wiki, conf = MediaWiki.dotfile('speed metal bot')
25
+ category_name = conf['category']
26
+ user_prefix = conf['user prefix']
27
+ template_name = conf['template']
28
+
29
+ category = wiki.category(category_name)
30
+ template = wiki.article("Template:#{template_name}")
31
+
32
+ puts "Category #{category_name}: #{category.articles.inspect}"
33
+
34
+ users = []
35
+ projects = []
36
+ category.articles.each { |name|
37
+ if name.index(user_prefix) and name.index('/').nil?
38
+ prefix, name = name.split(/:/, 2)
39
+ users << name
40
+ else
41
+ projects << name
42
+ end
43
+ }
44
+
45
+ ### Construct template ###
46
+ newtemplate = "<div align=\"center\" style=\"border: 1px solid black; clear: right;\">\n" +
47
+ "<div style=\"float: left; width: 64px; height: 64px;>[[Bild:Speed metal coding 64x64.jpg|left]]</div>\n" +
48
+ "<div style=\"margin-left: 70px; background-color: #e64200; font-size: large; height: 1.5em;\">'''Rübÿ Spëëd Mëtäl Cödïng'''</div>\n" +
49
+ "<div style=\"margin-left: 70px;\">'''Coders:''' "
50
+ users.each_with_index { |user,i|
51
+ newtemplate += " | " if i > 0
52
+ newtemplate += "[[User:#{user}|#{user}]]"
53
+ }
54
+
55
+ newtemplate += "</div>\n" +
56
+ "<div style=\"margin-left: 70px;\">'''Projects:''' "
57
+ projects.each_with_index { |project,i|
58
+ newtemplate += " | " if i > 0
59
+ newtemplate += "[[#{project}]]"
60
+ }
61
+ newtemplate += "<br/></div>\n" +
62
+ "</div>\n"
63
+
64
+ ### Submit template ###
65
+ if template.text != newtemplate
66
+ template.text = newtemplate
67
+ template.submit("Speed metal bot run", true)
68
+ end
69
+
70
+ ### Let template be used by all in category ###
71
+ category.articles.each { |name|
72
+ article = wiki.article(name)
73
+ unless article.text.index("{{#{template_name}}}")
74
+ puts "#{article.name} is in category but doesn't use template"
75
+ article.text.gsub!(/\n+$/, '')
76
+ article.text += "\n\n\n\n{{#{template_name}}}"
77
+ article.submit("This page must use the #{template_name} template!!!111")
78
+ end
79
+ }
@@ -0,0 +1,30 @@
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
+
21
+ $:.unshift('../lib')
22
+ require 'mediawiki/dotfile'
23
+
24
+ if ARGV.size != 1
25
+ puts "Usage: #{$0} <Article name>"
26
+ exit
27
+ end
28
+
29
+ wiki = MediaWiki.dotfile
30
+ puts wiki.article(ARGV[0]).text
@@ -0,0 +1,32 @@
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
+
21
+ $:.unshift('../lib')
22
+ require 'mediawiki/dotfile'
23
+
24
+ if ARGV.size != 3
25
+ puts "Usage: #{$0} <Article name> <file> <comment>"
26
+ exit
27
+ end
28
+
29
+ wiki = MediaWiki.dotfile
30
+ a = wiki.article(ARGV[0])
31
+ a.text = File.new(ARGV[1]).readlines.to_s
32
+ a.submit(ARGV[2])
@@ -0,0 +1,170 @@
1
+ =begin
2
+ This file is part of Ruby-MediaWiki.
3
+
4
+ Ruby-MediaWiki is free software: you can redistribute it and/or
5
+ modify it under the terms of the GNU General Public License as
6
+ published by the Free Software Foundation, either version 3 of the
7
+ License, or (at your option) any later version.
8
+
9
+ Ruby-MediaWiki 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
+ General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Ruby-MediaWiki. If not, see
16
+ <http://www.gnu.org/licenses/>.
17
+ =end
18
+
19
+
20
+ require 'uri'
21
+ require 'logger'
22
+
23
+
24
+ # Logger is required by article.rb
25
+ module MediaWiki
26
+ def self.logger
27
+ if defined? @@logger
28
+ @@logger
29
+ else
30
+ @@logger = Logger.new(STDERR)
31
+ end
32
+ end
33
+ end
34
+
35
+ require 'mediawiki/article'
36
+ require 'mediawiki/specialpage'
37
+ require 'mediawiki/category'
38
+ require 'mediawiki/minibrowser'
39
+
40
+ ##
41
+ # =Ruby-MediaWiki - manipulate MediaWiki pages from Ruby.
42
+ #
43
+ # Please note that documents spit out by MediaWiki *must* be valid
44
+ # XHTML (or XML)!
45
+ #
46
+ # You may not want to use MediaWiki::Wiki directly but let MediaWiki.dotfile
47
+ # create your instance. This gives you the power of the dotfile
48
+ # infrastructure. See sample apps and <tt>mediawikirc.sample</tt>.
49
+ module MediaWiki
50
+ ##
51
+ # There's no need for any language attribute, the "Special:" prefix
52
+ # works in any MediaWiki, regardless of localization settings.
53
+ class Wiki
54
+ ##
55
+ # The MiniBrowser instance used by this Wiki.
56
+ # This must be readable as it's used by Article and Category
57
+ # to fetch themselves.
58
+ attr_reader :browser
59
+
60
+ ##
61
+ # The URL-Path to index.php (without index.php) as given
62
+ # to Wiki#initialize
63
+ attr_reader :url
64
+
65
+ ##
66
+ # Initialize a new Wiki instance.
67
+ # url:: [String] URL-Path to index.php (without index.php), may containt <tt>user:password</tt> combination.
68
+ # user:: [String] If not nil, log in with that MediaWiki username (see Wiki#login)
69
+ # password:: [String] If not nil, log in with that MediaWiki password (see Wiki#login)
70
+ # loglevel:: [Integer] Loglevel, default is to log all messages >= Logger::WARN = 2
71
+ def initialize(url, user = nil, password = nil, loglevel = Logger::WARN)
72
+ if ENV['MEDIAWIKI_DEBUG']
73
+ MediaWiki::logger.level = Logger::DEBUG
74
+ else
75
+ MediaWiki::logger.level = loglevel
76
+ end
77
+
78
+ @url = URI.parse( url.match(/\/$/) ? url : url + '/' )
79
+ @browser = MiniBrowser.new(@url)
80
+
81
+ login( user, password ) if user and password
82
+ end
83
+
84
+ ##
85
+ # Log in into MediaWiki
86
+ #
87
+ # This is *not* HTTP authentication
88
+ # (put HTTP-Auth into [url] of Wiki#initialize!)
89
+ # user:: [String] MediaWiki username
90
+ # password:: [String] MediaWiki password
91
+ #
92
+ # May raise an exception if cannot authenticate
93
+ def login( username, password )
94
+ data = {'wpName' => username, 'wpPassword' => password, 'wpLoginattempt' => 'Log in'}
95
+ data = @browser.post_content( @url.path + 'index.php?title=Special:Userlogin&action=submitlogin', data )
96
+ if data =~ /<p class='error'>/
97
+ raise "Unable to authenticate as #{username}"
98
+ end
99
+ end
100
+
101
+ ##
102
+ # Return a new Category instance with given name,
103
+ # will be constructed with [self] (for MiniBrowser usage)
104
+ # name:: [String] Category name (to be prepended with "Category:")
105
+ def category(name)
106
+ Category.new(self, name)
107
+ end
108
+
109
+ ##
110
+ # Return a new Article instance with given name,
111
+ # will be constructed with [self] (for MiniBrowser usage)
112
+ # name:: [String] Article name
113
+ # section:: [Fixnum] Optional section number
114
+ def article(name, section = nil)
115
+ Article.new(self, name, section)
116
+ end
117
+
118
+ ##
119
+ # Retrieve all namespaces and their IDs, which could be used for Wiki#allpages
120
+ # result:: [Hash] String => Fixnum
121
+ def namespace_ids
122
+ ids = {}
123
+ SpecialPage.new( self, 'Special:Allpages', nil, false ).xhtml.each_element('//select[@name=\'namespace\']/option') do | o |
124
+ ids[o.text] = o.attributes['value'].to_i
125
+ end
126
+ ids
127
+ end
128
+
129
+ ##
130
+ # Returns the pages listed on "Special:Allpages"
131
+ #
132
+ # TODO: Handle big wikis with chunked Special:Allpages
133
+ # namespace_id:: Optional namespace for article index (see Wiki#namespace_ids to retrieve id)
134
+ # result:: [Array] of [String] Articlenames
135
+ def allpages(namespace_id=nil)
136
+ # Dirty, but works
137
+ article_name = 'Special:Allpages'
138
+ article_name += "&namespace=#{namespace_id}" if namespace_id
139
+
140
+ pages = []
141
+ SpecialPage.new( self, article_name, nil, false ).xhtml.each_element('table[2]/tr/td/a') do | a |
142
+ pages.push( a.text )
143
+ end
144
+ pages
145
+ end
146
+
147
+ ##
148
+ # Construct the URL to a specific article
149
+ #
150
+ # Uses the [url] the Wiki instance was constructed with,
151
+ # appends "index.php", the name parameter and, optionally,
152
+ # the section.
153
+ #
154
+ # Often called by Article, Category, ...
155
+ # name:: [String] Article name
156
+ # section:: [Fixnum] Optional section number
157
+ def article_url(name, section = nil)
158
+ "#{@url.path}index.php?title=#{CGI::escape(name.gsub(' ', '_'))}#{section ? "&section=#{CGI::escape(section.to_s)}" : ''}"
159
+ end
160
+
161
+ def full_article_url(name, section=nil)
162
+ uri = @url.dup
163
+ uri.path, uri.query = article_url(name, section).split(/\?/, 2)
164
+ uri.to_s
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+