qiita-export 0.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6442dd02c9dd12b8a17344ad0a9e3f6dd780c371
4
+ data.tar.gz: 1463061332a477bf955edcbd435db8a3c0fb6279
5
+ SHA512:
6
+ metadata.gz: 4668ef573aaa449d7d37248bc060a05700f555fd3bf16158d412b2809f20794130c1e5955d8cf15805966e2801ee861595a56deb79ae0970892007d4b76b943b
7
+ data.tar.gz: ec2cb0016242ce4a2ee41e0d8926facb234e4f77b06142a4e73371ff3f950f97f6f92995529f25c8618f1b342d14fdde3c6a315e899101b22b80e90e22ecacbd
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /vendor/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in qiita_export.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 akishin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ # QiitaExport
2
+
3
+ export tool for Qiita(http://qiita.com/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'qiita_export'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```
22
+ $ gem install qiita_export
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```
28
+ Usage: qiita-export [options]
29
+ -u, --url=url specify the URL for the Qiita(or Qiita Team).
30
+ -l, --url-list=filepath specify the file path of the URL list.
31
+ -U, --user-id=user_id specify the userid for the Qiita.
32
+ -k, --kobito=[Kobito.db] export Kobito.app database.
33
+ -t, --team=teamname export Qiita Team articles only.
34
+ -i, --image export with images.
35
+ -h, --html export in html format(experimental).
36
+ -o, --output-dir=dirpath specify the full path of destination directory.
37
+ -a, --api-token=token specify API token for Qiita.
38
+ ```
39
+
40
+ ## Contributing
41
+
42
+ 1. Fork it ( https://github.com/akishin/qiita_export/fork )
43
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
44
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
45
+ 4. Push to the branch (`git push origin my-new-feature`)
46
+ 5. Create a new Pull Request
47
+
48
+ ## License
49
+
50
+ MIT License
51
+
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ desc 'rake spec'
5
+ task :default => [:spec]
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = 'spec/*_spec.rb'
9
+ spec.rspec_opts = ['-cfd --backtrace']
10
+ end
11
+
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'rubygems'
4
+ require 'qiita-export'
5
+
6
+ QiitaExport::Config.configure(ARGV)
7
+ if QiitaExport::Config.empty?
8
+ print QiitaExport::Config.help
9
+ exit true
10
+ end
11
+
12
+ begin
13
+ QiitaExport::Config.validate!
14
+ rescue ArgumentError => e
15
+ $stderr.puts e.message
16
+ exit(1)
17
+ end
18
+
19
+ QiitaExport::Exporter::new.export
@@ -0,0 +1,10 @@
1
+ require 'qiita-export/version'
2
+ require 'qiita-export/image'
3
+ require 'qiita-export/article'
4
+ require 'qiita-export/config'
5
+ require 'qiita-export/exporter'
6
+ require 'qiita-export/fetcher/base'
7
+ require 'qiita-export/fetcher/kobito_fetcher'
8
+ require 'qiita-export/fetcher/api_fetcher'
9
+ require 'qiita-export/fetcher/url_fetcher'
10
+ require 'qiita-export/fetcher/user_fetcher'
@@ -0,0 +1,65 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'erb'
3
+
4
+ module QiitaExport
5
+ class Article
6
+ attr_reader :key, :url, :title, :raw_body, :rendered_body, :created_at,
7
+ :updated_at, :user_id, :images
8
+
9
+ HTML_TEMPLATE =<<-"EOS"
10
+ <!DOCTYPE html>
11
+ <html>
12
+ <head>
13
+ <meta charset="UTF-8" />
14
+ <title><%= @title %></title>
15
+ </head>
16
+ <body>
17
+ <h1><%= @title %></h1>
18
+ <%= @rendered_body %>
19
+ </body>
20
+ </html>
21
+ EOS
22
+
23
+ def initialize(key, url, title, raw_body, rendered_body, created_at, updated_at, user_id)
24
+ @key = key
25
+ @url = url
26
+ @title = title
27
+ @raw_body = raw_body
28
+ @rendered_body = rendered_body
29
+ @created_at = created_at
30
+ @updated_at = updated_at
31
+ @user_id = user_id
32
+ @images = Image.extract_urls(@key, @raw_body)
33
+ end
34
+
35
+ def save
36
+ save_dir = File.join(Config.export_dir_path, Config.team_name(@url), @key)
37
+
38
+ FileUtils.makedirs(save_dir) unless Dir.exists?(save_dir)
39
+
40
+ file_path = File.join(save_dir, Config.filename(title))
41
+ File.open(file_path, "w") { |f| f.write export_content }
42
+ if (Config.image_export?)
43
+ @images.each { |image| image.save(save_dir) }
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def export_content
50
+ if Config.html_export?
51
+ replace_img_src!(@rendered_body)
52
+ ERB.new(HTML_TEMPLATE).result(binding)
53
+ else
54
+ @raw_body
55
+ end
56
+ end
57
+
58
+ def replace_img_src!(html)
59
+ image_urls = html.scan(/<img[^src]+src="([^"]+)"[^>]+>/).flatten
60
+ image_urls.each do |image_url|
61
+ html.gsub!(image_url, "./#{Image::IMAGE_DIR}/#{File.basename(image_url)}")
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,184 @@
1
+ require 'optparse'
2
+
3
+ module QiitaExport
4
+ class Config
5
+
6
+ HOME_CONFIG_FILE = "~/.qiita-exportrc"
7
+ LOCAL_CONFIG_FILE = "./.qiita-exportrc"
8
+
9
+ DEFAULT_USER_AGENT = "QiitaExport Gem #{QiitaExport::VERSION}"
10
+
11
+ DEFAULT_HEADER = {
12
+ "User-Agent" => DEFAULT_USER_AGENT
13
+ }
14
+
15
+ DEFAULT_KOBITO_DB = "~/Library/Containers/com.qiita.Kobito/Data/Library/Kobito/Kobito.db"
16
+
17
+ class << self
18
+ def configure(argv)
19
+ @option = {}
20
+ @parser = OptionParser.new do |opt|
21
+ opt.version = QiitaExport::VERSION
22
+ opt.on('-u', '--url=url', 'specify the URL for the Qiita(or Qiita Team).') { |v| @option[:url] = v }
23
+ opt.on('-l', '--url-list=filepath', 'specify the file path of the URL list.') { |v| @option[:'url-list'] = v }
24
+ opt.on('-U', '--user-id=user_id', 'specify the userid for the Qiita.') { |v| @option[:'user-id'] = v }
25
+ opt.on('-k', '--kobito=[Kobito.db]', 'export Kobito.app database.') { |v| @option[:kobito] = v }
26
+ opt.on('-t', '--team=teamname', 'export Qiita Team articles only.') { |v| @option[:team] = v }
27
+ opt.on('-i', '--image', 'export with images.') { |v| @option[:image] = v }
28
+ opt.on('-h', '--html', 'export in html format(experimental).') { |v| @option[:html] = v }
29
+ opt.on('-o', '--output-dir=dirpath', 'specify the full path of destination directory.') { |v| @option[:'output-dir'] = v }
30
+ opt.on('-a', '--api-token=token', 'specify API token for Qiita.') { |v| @option[:'api-token'] = v }
31
+ end
32
+
33
+ # load home config
34
+ @parser.load(File.expand_path(HOME_CONFIG_FILE))
35
+
36
+ # load local config
37
+ @parser.load(File.expand_path(LOCAL_CONFIG_FILE))
38
+
39
+ # parse argv
40
+ @parser.parse!(argv)
41
+
42
+ self
43
+ end
44
+
45
+ def empty?
46
+ @option.empty?
47
+ end
48
+
49
+ def help
50
+ @parser.help
51
+ end
52
+
53
+ def validate!
54
+ if present?(@option[:'url-list']) && !File.exist?(@option[:'url-list'])
55
+ fail ArgumentError.new("-l (#{@option[:'url-list']}) does not exist.")
56
+ end
57
+
58
+ if kobito? && !File.exist?(kobito_db)
59
+ fail ArgumentError.new("#{kobito_db} does not exist.")
60
+ end
61
+
62
+ if kobito? && api?
63
+ fail ArgumentError.new("if you specify option --kobito, you cannot specify option --url, --url-list and --user-id.")
64
+ end
65
+ end
66
+
67
+ def kobito?
68
+ @option.key?(:kobito)
69
+ end
70
+
71
+ def api?
72
+ present?(@option[:url]) || present?(@option[:'url-list']) || present?(@option[:'user-id'])
73
+ end
74
+
75
+ def user?
76
+ present?(@option[:'user-id'])
77
+ end
78
+
79
+ def team?
80
+ present?(@option[:team])
81
+ end
82
+
83
+ def file_export?
84
+ present?(@option[:'output-dir'])
85
+ end
86
+
87
+ def html_export?
88
+ @option[:html]
89
+ end
90
+
91
+ def image_export?
92
+ @option[:image]
93
+ end
94
+
95
+ def team_url?(url)
96
+ url !~ /^https?:\/\/qiita\.com/
97
+ end
98
+
99
+ DOMAIN_PATTERN = Regexp.new("https?://([^/]+)/")
100
+ def team_name(url = nil)
101
+ if (kobito? || user?) && team?
102
+ @option[:team]
103
+ elsif api? && team_url?(url)
104
+ url.match(DOMAIN_PATTERN)[1].split('.')[0]
105
+ else
106
+ ""
107
+ end
108
+ end
109
+
110
+ def article_urls
111
+ urls = []
112
+ urls << @option[:url] if present?(@option[:url])
113
+
114
+ if present?(@option[:'url-list'])
115
+ open(@option[:'url-list']) { |io|
116
+ io.each_line { |line|
117
+ url = line.chop
118
+ next if blank?(url)
119
+ urls << url
120
+ }
121
+ }
122
+ end
123
+ urls
124
+ end
125
+
126
+ def kobito_db
127
+ if blank?(@option[:kobito])
128
+ File.expand_path(DEFAULT_KOBITO_DB)
129
+ else
130
+ File.expand_path(@option[:kobito])
131
+ end
132
+ end
133
+
134
+ def api_token
135
+ @option[:'api-token']
136
+ end
137
+
138
+ def has_api_token?
139
+ present?(@option[:'api-token'])
140
+ end
141
+
142
+ def default_header
143
+ DEFAULT_HEADER.clone
144
+ end
145
+
146
+ def auth_header
147
+ header = default_header
148
+ header["Authorization"] = "Bearer #{api_token}"
149
+ header
150
+ end
151
+
152
+ def user_id
153
+ @option[:'user-id']
154
+ end
155
+
156
+ def export_dir_path
157
+ if user?
158
+ File.join(File.expand_path(@option[:'output-dir'].strip), user_id)
159
+ else
160
+ File.expand_path(@option[:'output-dir'].strip)
161
+ end
162
+ end
163
+
164
+ def filename(title)
165
+ return "" if !html_export? && blank?(title)
166
+ if html_export?
167
+ "index.html"
168
+ else
169
+ "#{title.gsub(/\//, ':')}.md"
170
+ end
171
+ end
172
+
173
+ private
174
+
175
+ def blank?(str)
176
+ str.nil? || str.empty?
177
+ end
178
+
179
+ def present?(str)
180
+ !blank?(str)
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,45 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module QiitaExport
4
+ class Exporter
5
+
6
+ def initialize
7
+ end
8
+
9
+ def export
10
+ fetcher = create_fetcher
11
+ articles = fetcher.find_articles
12
+ if (Config.file_export?)
13
+ export_file(articles)
14
+ else
15
+ export_console(articles)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def create_fetcher
22
+ if Config.kobito?
23
+ QiitaExport::Fetcher::KobitoFetcher.new
24
+ elsif Config.user?
25
+ QiitaExport::Fetcher::UserFetcher.new
26
+ else
27
+ QiitaExport::Fetcher::UrlFetcher.new
28
+ end
29
+ end
30
+
31
+ def export_console(articles)
32
+ articles.each do |article|
33
+ $stdout.puts("key: #{article.key} title: #{article.title} url: #{article.url} created_at: #{article.created_at} updated_at: #{article.updated_at}")
34
+ end
35
+ end
36
+
37
+ def export_file(articles)
38
+ $stdout.puts "export articles to #{Config.export_dir_path}"
39
+ FileUtils.makedirs(Config.export_dir_path) unless Dir.exists?(Config.export_dir_path)
40
+ articles.each do |article|
41
+ article.save
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,42 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'json'
3
+ require 'uri'
4
+
5
+ module QiitaExport::Fetcher
6
+ class ApiFetcher < Base
7
+
8
+ DEFAULT_HOST = "qiita.com"
9
+
10
+ protected
11
+
12
+ def to_article(res)
13
+ key = res['id']
14
+ url = res['url']
15
+ title = res['title']
16
+ raw_body = res['body']
17
+ rendered_body = res['rendered_body']
18
+ created_at = res['created_at']
19
+ updated_at = res['updated_at']
20
+ user_id = res['user_id']
21
+
22
+ ::QiitaExport::Article.new(key, url, title, raw_body, rendered_body, created_at, updated_at, user_id)
23
+ end
24
+
25
+ def article_key(url)
26
+ File.basename(url)
27
+ end
28
+
29
+ def request_header
30
+ has_api_token? ? auth_header : default_header
31
+ end
32
+
33
+ def api_domain(url = nil)
34
+ if url.nil?
35
+ team? ? "#{team_name}.#{DEFAULT_HOST}" : DEFAULT_HOST
36
+ else
37
+ URI.parse(url).host
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'forwardable'
3
+
4
+ module QiitaExport::Fetcher
5
+ class Base
6
+ extend Forwardable
7
+
8
+ def_delegators :@config, :kobito?, :kobito_db, :file_export?,
9
+ :export_dir_path, :team?, :team_name,
10
+ :article_urls, :has_api_token?, :api_token,
11
+ :user_id, :default_header, :auth_header
12
+
13
+ def initialize
14
+ @config = ::QiitaExport::Config
15
+ end
16
+
17
+ def find_articles
18
+ raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,78 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'sqlite3'
4
+ require 'time'
5
+
6
+ module QiitaExport::Fetcher
7
+ class KobitoFetcher < Base
8
+
9
+ SELECT =<<-"EOS"
10
+ SELECT
11
+ i.zurl,
12
+ i.ztitle,
13
+ i.zraw_body,
14
+ i.zbody,
15
+ i.zposted_at,
16
+ i.zcreated_at,
17
+ i.zupdated_at,
18
+ i.zupdated_at_on_qiita,
19
+ t.zurl_name
20
+ FROM
21
+ zitem i left outer join zteam t on i.zteam = t.z_pk
22
+ WHERE
23
+ zin_trash is null
24
+ EOS
25
+
26
+ ORDER = " ORDER BY i.zcreated_at"
27
+
28
+ def find_articles
29
+ where = if team?
30
+ " and zurl_name = :team"
31
+ else
32
+ " and zteam is null"
33
+ end
34
+ query = "#{SELECT}#{where}#{ORDER}"
35
+
36
+ db = SQLite3::Database.new(kobito_db)
37
+ db.results_as_hash = true
38
+
39
+ stmt = db.prepare(query)
40
+ stmt.bind_param("team", team_name) if team?
41
+ rs = stmt.execute
42
+
43
+ articles = []
44
+ while(row = rs.next)
45
+ articles << to_article(row)
46
+ end
47
+ articles
48
+ ensure
49
+ stmt.close if stmt
50
+ db.close if db
51
+ end
52
+
53
+ private
54
+
55
+ def to_article(row)
56
+ key = File.basename(row['ZURL'])
57
+ url = row['ZURL']
58
+ title = row['ZTITLE']
59
+ raw_body = row['ZRAW_BODY']
60
+ rendered_body = row['ZBODY']
61
+
62
+ zposted_at = convert_timestamp(row['ZPOSTED_AT'])
63
+ zcreated_at = convert_timestamp(row['ZCREATED_AT'])
64
+ zupdated_at_on_qiita = convert_timestamp(row['ZUPDATED_AT_ON_QIITA'])
65
+ zupdated_at = convert_timestamp(row['ZUPDATED_AT'])
66
+
67
+ # puts "key: #{key} zposted_at: #{zposted_at} zcreated_at: #{zcreated_at} zupdated_at_on_qiita: #{zupdated_at_on_qiita} zupdated_at: #{zupdated_at}"
68
+ ::QiitaExport::Article.new(key, url, title, raw_body, rendered_body, zcreated_at, zupdated_at, 'kobito_user')
69
+ end
70
+
71
+ BASE_DATE = Time.new(2001, 1, 1, 0, 0, 0, 0).to_i
72
+ def convert_timestamp(timestamp)
73
+ Time.at(timestamp + BASE_DATE).iso8601
74
+ end
75
+ end
76
+ end
77
+
78
+
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'json'
3
+ require 'open-uri'
4
+
5
+ module QiitaExport::Fetcher
6
+ class UrlFetcher < ApiFetcher
7
+
8
+ def find_articles
9
+ articles = []
10
+ article_urls.each do |url|
11
+ articles << to_article(find_article(url))
12
+ end
13
+ articles
14
+ end
15
+
16
+ private
17
+
18
+ def find_article(url)
19
+ open("https://#{api_domain(url)}/api/v2/items/#{article_key(url)}", request_header) do |io|
20
+ JSON.parse(io.read)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'json'
3
+ require 'open-uri'
4
+
5
+ module QiitaExport::Fetcher
6
+ class UserFetcher < ApiFetcher
7
+
8
+ PER_PAGE = 100
9
+
10
+ def find_articles
11
+ articles = []
12
+ page = 1
13
+ while true
14
+ user_articles = find_user_articles(page)
15
+ break if user_articles.empty?
16
+
17
+ user_articles.each do |user_article|
18
+ articles << to_article(user_article)
19
+ end
20
+
21
+ page += 1
22
+ sleep(0.3)
23
+ end
24
+ articles.sort { |a, b| a.created_at <=> b.created_at }
25
+ end
26
+
27
+ private
28
+
29
+ def find_user_articles(page)
30
+ open("https://#{api_domain}/api/v2/users/#{user_id}/items?page=#{page}&per_page=#{PER_PAGE}", request_header) do |io|
31
+ JSON.parse(io.read)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,49 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'fileutils'
3
+ require 'uri'
4
+
5
+ module QiitaExport
6
+ class Image
7
+ attr_reader :key, :url
8
+
9
+ IMAGE_DIR = "images"
10
+
11
+ def initialize(key, url)
12
+ @key = key
13
+ @url = url
14
+ end
15
+
16
+ def self.extract_urls(key, markdown)
17
+ image_urls = markdown.scan(/!\[.*?\]\((.+?)(?: \".*?\")?\)/).flatten
18
+ image_urls.map do |image_url|
19
+ new(key, image_url)
20
+ end
21
+ end
22
+
23
+ def require_auth?
24
+ @url !~ /qiita-image-store.s3.amazonaws.com/
25
+ end
26
+
27
+ def request_header
28
+ require_auth? ? Config.auth_header : Config.default_header
29
+ end
30
+
31
+ def filename
32
+ "#{File.basename(url)}"
33
+ end
34
+
35
+ def save(path)
36
+ image_dir = File.join(File.expand_path(path), IMAGE_DIR)
37
+
38
+ FileUtils.makedirs(image_dir) unless Dir.exists?(image_dir)
39
+
40
+ file_path = File.join(image_dir, filename)
41
+
42
+ open(file_path, 'wb') do |out|
43
+ open(@url, request_header) do |image|
44
+ out.write(image.read)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,4 @@
1
+ module QiitaExport
2
+ VERSION = '0.0.1'
3
+ end
4
+
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'qiita-export/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "qiita-export"
8
+ spec.version = QiitaExport::VERSION
9
+ spec.authors = ["Shin Akiyama"]
10
+ spec.email = ["akishin999@gmail.com"]
11
+ spec.summary = %q{export tool for Qiita}
12
+ spec.description = %q{export tool for Qiita}
13
+ spec.homepage = "https://github.com/akishin/qiita-export"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.bindir = 'bin'
21
+
22
+ spec.add_dependency "sqlite3"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "3.4.0"
27
+ end
@@ -0,0 +1,47 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require File.expand_path(File.join('..', 'spec_helper'), File.dirname(__FILE__))
4
+ require 'qiita-export'
5
+
6
+ describe QiitaExport::Config do
7
+ let(:valid_url) { 'http://qiita.com/akishin/items/61630d628f4c8e141ef2' }
8
+ let(:valid_kobito_db) { File.expand_path(QiitaExport::Config::DEFAULT_KOBITO_DB) }
9
+ let(:valid_team_name) { 'example' }
10
+ let(:valid_argv) {
11
+ [
12
+ '--url', valid_url,
13
+ '--kobito', valid_kobito_db,
14
+ '--image',
15
+ '--html',
16
+ '--team', valid_team_name,
17
+ ]
18
+ }
19
+
20
+ describe ".configure" do
21
+
22
+ context "with arguments" do
23
+ let(:arguments) do
24
+ valid_argv
25
+ end
26
+
27
+ subject do
28
+ described_class.configure(arguments)
29
+ end
30
+
31
+ it "returns a QiitaExport::Config" do
32
+ expect(subject).to eq(QiitaExport::Config)
33
+ end
34
+ it { expect(subject.article_urls).to include(valid_url) }
35
+ it { expect(subject.kobito_db).to eq(valid_kobito_db) }
36
+ it { expect(subject.api?).to be_truthy }
37
+ it { expect(subject.image_export?).to be_truthy }
38
+ it { expect(subject.html_export?).to be_truthy }
39
+ it { expect(subject.team?).to be_truthy }
40
+ it { expect(subject.team_name).to eq(valid_team_name) }
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+
@@ -0,0 +1,80 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require File.expand_path(File.join('..', 'spec_helper'), File.dirname(__FILE__))
4
+ require 'qiita-export'
5
+
6
+ describe QiitaExport::Image do
7
+ let(:valid_key) { '99999999999999999999' }
8
+ let(:valid_url) { 'http://qiita-image-store.s3.amazonaws.com/example.jpg' }
9
+
10
+ describe ".new" do
11
+
12
+ context "with arguments" do
13
+ let(:arguments) do
14
+ [valid_key, valid_url]
15
+ end
16
+
17
+ subject do
18
+ described_class.new(*arguments)
19
+ end
20
+
21
+ it "returns a QiitaExport::Image" do
22
+ expect(subject).to be_an_instance_of(QiitaExport::Image)
23
+ end
24
+ it { expect(subject.key).to eq(valid_key) }
25
+ it { expect(subject.url).to eq(valid_url) }
26
+ end
27
+
28
+ context "without any arguments" do
29
+ let(:arguments) do
30
+ []
31
+ end
32
+
33
+ it "raise ArgumentError" do
34
+ expect {
35
+ described_class.new(*arguments)
36
+ }.to raise_error(ArgumentError)
37
+ end
38
+ end
39
+ end
40
+
41
+ let(:include_images) {
42
+ <<-"EOS"
43
+ ## Example Markdown
44
+ ![foo.png](https://example.com/foo.png "foo.png")
45
+ ![bar.png](https://example.com/bar.png)
46
+ EOS
47
+ }
48
+
49
+ let(:not_include_images) {
50
+ <<-"EOS"
51
+ ## Example Markdown
52
+ ### Test1
53
+ ### Test2
54
+ EOS
55
+ }
56
+
57
+ describe ".extract_urls" do
58
+ context "when there is image urls" do
59
+ subject do
60
+ described_class.extract_urls(valid_key, include_images)
61
+ end
62
+
63
+ it { expect(subject).not_to be_empty }
64
+ it { expect(subject.length).to eq(2) }
65
+ it { expect(subject.first).to be_an_instance_of(QiitaExport::Image) }
66
+ it { expect(subject.first.url).to eq('https://example.com/foo.png') }
67
+ it { expect(subject.last).to be_an_instance_of(QiitaExport::Image) }
68
+ it { expect(subject.last.url).to eq('https://example.com/bar.png') }
69
+ end
70
+
71
+ context "when there is no image urls" do
72
+ subject do
73
+ described_class.extract_urls(valid_key, not_include_images)
74
+ end
75
+ it { expect(subject).to be_empty }
76
+ end
77
+ end
78
+ end
79
+
80
+
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rspec'
4
+
5
+ RSpec.configure do |config|
6
+ config.filter_run :focus
7
+ config.run_all_when_everything_filtered = true
8
+ end
9
+
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qiita-export
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Shin Akiyama
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sqlite3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
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.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
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: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.4.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 3.4.0
69
+ description: export tool for Qiita
70
+ email:
71
+ - akishin999@gmail.com
72
+ executables:
73
+ - qiita-export
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/qiita-export
83
+ - lib/qiita-export.rb
84
+ - lib/qiita-export/article.rb
85
+ - lib/qiita-export/config.rb
86
+ - lib/qiita-export/exporter.rb
87
+ - lib/qiita-export/fetcher/api_fetcher.rb
88
+ - lib/qiita-export/fetcher/base.rb
89
+ - lib/qiita-export/fetcher/kobito_fetcher.rb
90
+ - lib/qiita-export/fetcher/url_fetcher.rb
91
+ - lib/qiita-export/fetcher/user_fetcher.rb
92
+ - lib/qiita-export/image.rb
93
+ - lib/qiita-export/version.rb
94
+ - qiita-export.gemspec
95
+ - spec/qiita-export/config_spec.rb
96
+ - spec/qiita-export/image_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: https://github.com/akishin/qiita-export
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.4.5
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: export tool for Qiita
122
+ test_files:
123
+ - spec/qiita-export/config_spec.rb
124
+ - spec/qiita-export/image_spec.rb
125
+ - spec/spec_helper.rb