mediawiki-page-replaceable_content 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bde3b8a6145a69b9889ba69541ceb7f81cc5531f
4
+ data.tar.gz: 5dd4fe8563ea3fc504294fb77a0b94cc1f50da89
5
+ SHA512:
6
+ metadata.gz: 0cd940ca714638388cbbafa70ee1bd84b145a9646a3d6c6a8f246ba1aca35838a89b0755466af37ad0e4e270bc99db7422268c853236b8e31a043585c7e409a4
7
+ data.tar.gz: df3c57e34c1e68013045a74e833db3b084a7b955a3e160f4227496f00c19639175c4e0cbcb2e95b2f05acf0959011f1f2c6eb90c533c2e00e87d74835a33cf22
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.rubocop-https---raw-githubusercontent-com-everypolitician-everypolitician-data-master--rubocop-base-yml
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.1
3
+
4
+ inherit_from:
5
+ - https://raw.githubusercontent.com/everypolitician/everypolitician-data/master/.rubocop_base.yml
6
+
7
+ Layout/AlignHash:
8
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.1
6
+ - 2.2
7
+ - 2.3.3
8
+ before_install: gem install bundler -v 1.15.3
9
+ script:
10
+ - bundle exec rake
11
+ - bash <(curl -fsSL https://github.com/everypolitician/ensure-regression-tests/raw/master/ensure-regression-tests)
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
+ and this project adheres to [Semantic Versioning](http://semver.org/).
7
+
8
+ ## Unreleased
9
+
10
+ ### Added
11
+
12
+ - Add notes about new features here.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in mediawiki-page-replaceable_content.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Mark Longair
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # MediaWiki::Page::ReplaceableContent
2
+
3
+ This gem provides a class,
4
+ `MediaWiki::Page::ReplaceableContent`, to help you
5
+ programmatically rewrite MediaWiki pages based on the parameters
6
+ of a template tag in that page. (This is a model used by the
7
+ [Listeria](https://tools.wmflabs.org/listeria/) bot, for
8
+ example.)
9
+
10
+ See the "Usage" section below for an example.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'mediawiki-page-replaceable_content'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install mediawiki-page-replaceable_content
27
+
28
+ ## Usage
29
+
30
+ To use the `ReplaceableContent` class, you must first create a
31
+ `Client` object, which specifies the MediaWiki site on which you
32
+ want to rewrite a page, and the username and password for
33
+ authentication.
34
+
35
+ ```ruby
36
+ require 'mediawiki/client'
37
+
38
+ client = MediaWiki::Client.new(
39
+ site: 'www.wikidata.org',
40
+ username: ENV['WIKI_USERNAME'],
41
+ password: ENV['WIKI_PASSWORD']
42
+ )
43
+ ```
44
+
45
+ Then you can use that to create a `ReplaceableContent` class,
46
+ which specifies a particular page and the template on that page
47
+ that your content will be placed directly after:
48
+
49
+ ```ruby
50
+ require 'mediawiki/page'
51
+
52
+ section = MediaWiki::Page::ReplaceableContent.new(
53
+ client: client,
54
+ title: 'User:Mhl20/Fibonnacci test',
55
+ template: 'Fibonacci'
56
+ )
57
+ ```
58
+
59
+ For example, suppose that page at
60
+ https://www.wikidata.org/wiki/User:Mhl20/Fibonnacci_test had the
61
+ following content:
62
+
63
+ ```
64
+ Here are some Fibonacci numbers:
65
+
66
+ {{Fibonacci
67
+ |max_fib=10
68
+ }}
69
+
70
+ You can find more about them here:
71
+ https://en.wikipedia.org/wiki/Fibonacci_number
72
+ ```
73
+
74
+ Then you could rewrite it, using the `ReplaceableContent` object
75
+ created above, with:
76
+
77
+ ```ruby
78
+ def fibonacci_numbers(limit)
79
+ numbers = []
80
+ i, j = 0, 1
81
+ while i <= limit
82
+ numbers << i
83
+ i, j = j, i + j
84
+ end
85
+ numbers
86
+ end
87
+
88
+ def wikitext_fibonacci_rows(limit)
89
+ fibs = fibonacci_numbers(limit)
90
+ "|-\n" + 0.upto(fibs.length - 1).map { |f| "| ''F''<sub>#{f}</sub>\n" }.join('') +
91
+ "|-\n" + fibs.map { |n| "| #{n}\n" }.join('')
92
+ end
93
+
94
+ def wikitext_fibonacci(limit)
95
+ "=== Some Fibonacci numbers ===\n:{| class=\"wikitable\"\n" +
96
+ wikitext_fibonacci_rows(limit) +
97
+ '|}'
98
+ end
99
+
100
+ limit = Integer(section.params[:max_fib])
101
+ section.replace_output(
102
+ wikitext_fibonacci(limit),
103
+ "Rewrote with numbers up to #{limit}"
104
+ )
105
+ ```
106
+
107
+ The result of running that would be that the page had the
108
+ following wikitext:
109
+
110
+ ```
111
+ Here are some Fibonacci numbers:
112
+
113
+ {{Fibonacci
114
+ |max_fib=10
115
+ }}
116
+ === Some Fibonacci numbers ===
117
+ :{| class="wikitable"
118
+ |-
119
+ | ''F''<sub>0</sub>
120
+ | ''F''<sub>1</sub>
121
+ | ''F''<sub>2</sub>
122
+ | ''F''<sub>3</sub>
123
+ | ''F''<sub>4</sub>
124
+ | ''F''<sub>5</sub>
125
+ | ''F''<sub>6</sub>
126
+ |-
127
+ | 0
128
+ | 1
129
+ | 1
130
+ | 2
131
+ | 3
132
+ | 5
133
+ | 8
134
+ |}
135
+ <!-- OUTPUT END Rewrote with numbers up to 10 -->
136
+
137
+ You can find more about them here:
138
+ https://en.wikipedia.org/wiki/Fibonacci_number
139
+ ```
140
+
141
+ On subsequent uses, only the text between the template tag and
142
+ the `<!-- OUTPUT END ... --->` comment will be rewritten.
143
+
144
+ If you need to rely on the previous content, you can get that
145
+ with `section.existing_content`.
146
+
147
+ ## Development
148
+
149
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
150
+
151
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
152
+
153
+ ## Contributing
154
+
155
+ Bug reports and pull requests are welcome on GitHub at https://github.com/everypolitician/mediawiki-page-replaceable_content
156
+
157
+ ## License
158
+
159
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ require 'rubocop/rake_task'
11
+ RuboCop::RakeTask.new
12
+
13
+ task default: %i[test rubocop]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'mediawiki/client'
5
+ require 'mediawiki/page'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/setup'
3
+
4
+ require 'mediawiki/client'
5
+ require 'mediawiki/page'
6
+
7
+ client = MediaWiki::Client.new(
8
+ site: 'www.wikidata.org',
9
+ username: ENV['WIKI_USERNAME'],
10
+ password: ENV['WIKI_PASSWORD']
11
+ )
12
+
13
+ section = MediaWiki::Page::ReplaceableContent.new(
14
+ client: client,
15
+ title: 'User:Mhl20/Fibonnacci test',
16
+ template: 'Fibonacci'
17
+ )
18
+
19
+ def fibonacci_numbers(limit)
20
+ numbers = []
21
+ i = 0
22
+ j = 1
23
+ while i <= limit
24
+ numbers << i
25
+ i = j
26
+ j = i + j
27
+ end
28
+ numbers
29
+ end
30
+
31
+ def wikitext_fibonacci_rows(limit)
32
+ fibs = fibonacci_numbers(limit)
33
+ "|-\n" + 0.upto(fibs.length - 1).map { |f| "| ''F''<sub>#{f}</sub>\n" }.join('') +
34
+ "|-\n" + fibs.map { |n| "| #{n}\n" }.join('')
35
+ end
36
+
37
+ def wikitext_fibonacci(limit)
38
+ "=== Some Fibonacci numbers ===\n:{| class=\"wikitable\"\n" +
39
+ wikitext_fibonacci_rows(limit) +
40
+ '|}'
41
+ end
42
+
43
+ limit = Integer(section.params[:max_fib])
44
+ section.replace_output(
45
+ wikitext_fibonacci(limit),
46
+ "Rewrote with numbers up to #{limit}"
47
+ )
@@ -0,0 +1,27 @@
1
+ require 'mediawiki_api'
2
+
3
+ module MediaWiki
4
+ class Client
5
+ def initialize(site:, username:, password:)
6
+ @site = site
7
+ @username = username
8
+ @password = password
9
+ end
10
+
11
+ extend Forwardable
12
+ def_delegators :wrapped_client, :edit, :get_wikitext
13
+
14
+ private
15
+
16
+ attr_accessor :site, :username, :password
17
+
18
+ def wrapped_client
19
+ @wrapped_client ||= MediawikiApi::Client.new("https://#{site}/w/api.php").tap do |c|
20
+ result = c.log_in(username, password)
21
+ unless result['result'] == 'Success'
22
+ raise "MediawikiApi::Client#log_in failed: #{result}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,98 @@
1
+ require 'mediawiki_api'
2
+
3
+ module MediaWiki
4
+ module Page
5
+ class ReplaceableContent
6
+ def initialize(client:, title:, template:)
7
+ @client = client
8
+ @title = title
9
+ @template = template
10
+ end
11
+
12
+ def existing_content
13
+ page_parts[:to_replace]
14
+ end
15
+
16
+ def reassemble_page(new_content, run_comment = '')
17
+ "%<before>s{{%<template_name>s%<parameters>s}}
18
+ #{new_content}
19
+ <!-- OUTPUT END #{run_comment} -->
20
+ %<keep>s" % page_parts
21
+ end
22
+
23
+ def replace_output(new_content, run_comment = '')
24
+ new_wikitext = reassemble_page(new_content, run_comment)
25
+ client.edit(title: title, text: new_wikitext)
26
+ end
27
+
28
+ def params
29
+ # Returns the named parameters from the template tag as a Hash
30
+ # where the keys are symbolized versions of the parameter
31
+ # names.
32
+ # FIXME: untemplate these using the MediaWiki API before
33
+ # returning them.
34
+ all_parameters.map do |p|
35
+ m = /(.*?)=(.*)/m.match(p)
36
+ [m[1].strip.to_sym, m[2]]
37
+ end.to_h
38
+ end
39
+
40
+ private
41
+
42
+ attr_accessor :client, :title, :template
43
+
44
+ def wikitext
45
+ @wikitext ||= client.get_wikitext(title).body
46
+ end
47
+
48
+ def template_re
49
+ # FIXME: there are obviously better ways of doing this parsing
50
+ # than with a regular expression. e.g. there is an EBNF
51
+ # version of the MediaWiki grammar which we could use to
52
+ # generate a proper parser.
53
+ /
54
+ ^(?<before>.*?)
55
+ \{\{
56
+ (?<template_name>#{Regexp.quote(template)})
57
+ (?<parameters>.*?)
58
+ \}\}\n
59
+ (?<after>.*)$
60
+ /xm
61
+ end
62
+
63
+ def page_parts
64
+ return @page_parts if @page_parts
65
+ m = template_re.match(wikitext)
66
+ raise "The template '#{template}' was not found in '#{title}'" unless m
67
+ parts = matchdata_to_h(m)
68
+ @page_parts = parts.merge(split_after(parts[:after]))
69
+ end
70
+
71
+ def split_after(after)
72
+ # The part of the page after the template may or may not have
73
+ # the special HTML comment that marks the end of the previous
74
+ # output; if it's not there we insert the new content right
75
+ # after the template tag.
76
+ if after =~ /^(?<to_replace>.*?)\n<!-- OUTPUT END (?:.*?)-->\n(?<keep>.*)/m
77
+ matchdata_to_h(Regexp.last_match)
78
+ else
79
+ { to_replace: '', keep: after }
80
+ end
81
+ end
82
+
83
+ def all_parameters
84
+ # This returns all parameters, including anonymous, numbered and
85
+ # named parameters. (Though we only handle named parameters at
86
+ # the moment.)
87
+ page_parts[:parameters].split('|').select do |s|
88
+ s.strip!
89
+ s.empty? ? nil : s
90
+ end
91
+ end
92
+
93
+ def matchdata_to_h(md)
94
+ md.names.map(&:to_sym).zip(md.captures).to_h
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'mediawiki-page-replaceable_content'
8
+ spec.version = '0.1.0'
9
+ spec.authors = ['EveryPolitician']
10
+ spec.email = ['team@everypolitician.org']
11
+ spec.licenses = ['MIT']
12
+
13
+ spec.summary = 'Rewrite content after a template tag based on the template parameters'
14
+ spec.homepage = 'https://github.com/everypolitician/mediawiki-page-replaceable_content'
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
+ else
21
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
22
+ 'public gem pushes.'
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
+ f.match(%r{^(test|spec|features)/})
27
+ end
28
+ spec.bindir = 'exe'
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ['lib']
31
+
32
+ spec.add_runtime_dependency 'mediawiki_api', '~> 0.7'
33
+
34
+ spec.add_development_dependency 'bundler', '~> 1.15'
35
+ spec.add_development_dependency 'rake', '~> 10.0'
36
+ spec.add_development_dependency 'minitest', '~> 5.0'
37
+ spec.add_development_dependency 'pry', '~> 0.10'
38
+ spec.add_development_dependency 'rubocop', '~> 0.49'
39
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mediawiki-page-replaceable_content
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - EveryPolitician
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-08-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mediawiki_api
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.10'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.49'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.49'
97
+ description:
98
+ email:
99
+ - team@everypolitician.org
100
+ executables:
101
+ - fibonacci_example
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rubocop.yml"
107
+ - ".travis.yml"
108
+ - CHANGELOG.md
109
+ - Gemfile
110
+ - LICENSE.txt
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - exe/fibonacci_example
116
+ - lib/mediawiki/client.rb
117
+ - lib/mediawiki/page.rb
118
+ - mediawiki-page-replaceable_content.gemspec
119
+ homepage: https://github.com/everypolitician/mediawiki-page-replaceable_content
120
+ licenses:
121
+ - MIT
122
+ metadata:
123
+ allowed_push_host: https://rubygems.org
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 2.5.1
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: Rewrite content after a template tag based on the template parameters
144
+ test_files: []