qiita_picks 0.1.2
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +160 -0
- data/Rakefile +7 -0
- data/bin/qiita_picks +137 -0
- data/lib/qiita_picks.rb +48 -0
- data/lib/qiita_picks/generator.rb +116 -0
- data/lib/qiita_picks/mailer.rb +42 -0
- data/lib/qiita_picks/picker.rb +128 -0
- data/lib/qiita_picks/templates/article.erb +5 -0
- data/lib/qiita_picks/templates/layout.erb +11 -0
- data/lib/qiita_picks/version.rb +3 -0
- data/qiita_picks.gemspec +43 -0
- data/spec/qiita_picks_spec.rb +7 -0
- data/spec/spec_helper.rb +2 -0
- metadata +215 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dd111977c59c8d4025f8b77947b3819d448837d4
|
4
|
+
data.tar.gz: 11f8e3254e1e48cb600e8342eee4f022747196f6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e8226211760dcf4392b22710294c0eb62cb6e86cad24345efb8f0bb5c0a2e3dd7004d303ba4afdb34da273a0d290999b89a4cbdf17163e98a09bad8f0ae670a1
|
7
|
+
data.tar.gz: 1b4221573895799dbbaaa24de9ba9269bf29452bafa8d316556aa0abb3a72b3ee61e8b2472857d7c9a079f0502b9adce3909b97e1a89119e2f85f1a180c9ed53
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 @ HentecoLabs Inc
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# QiitaPicks
|
2
|
+
|
3
|
+
**:fork_and_knife:Qiita[キータ]に投稿された記事を “つまんで” まとめPDFを生成:fork_and_knife:**
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
**Generate PDF/HTML** from articles posted on **[qiita.com](http://qiita.com/)**.
|
8
|
+
Uses **[wkhtmltopdf](http://wkhtmltopdf.org/)** on the back-end which renders HTML using Webkit.
|
9
|
+
|
10
|
+
## できること
|
11
|
+
|
12
|
+
#### **まとめPDFをコマンド一発で生成**
|
13
|
+
|
14
|
+
`qiita_picks`コマンドで、次の「まとめPDF」が生成できます。
|
15
|
+
|
16
|
+
1. **指定URL**のまとめPDF
|
17
|
+
1. **特定のユーザが投稿した記事**のまとめPDF
|
18
|
+
1. **特定のユーザがストックした記事**のまとめPDF
|
19
|
+
1. **『先週ストックが多かった投稿ベスト20』メールに掲載された記事**のまとめPDF
|
20
|
+
1. **『今週Qiitaでストックした記事』メールに掲載された記事**のまとめPDF
|
21
|
+
1. **はてなブックマークにブックマークされた記事(人気)**のまとめPDF
|
22
|
+
1. **はてなブックマークにブックマークされた記事(新着)**のまとめPDF
|
23
|
+
|
24
|
+
#### **まとめPDFは、印刷・閲覧に最適化**
|
25
|
+
|
26
|
+
印刷向けにスタイルシートを調整しています。
|
27
|
+
|
28
|
+
#### **まとめPDFは、Gmailで送信可能**
|
29
|
+
|
30
|
+
- Gmailの送受信には「**[ruby-gmail](https://github.com/dcparker/ruby-gmail)**」を利用しています。
|
31
|
+
- メールは送受信共に、利用者自身となります。
|
32
|
+
|
33
|
+
## Installation
|
34
|
+
|
35
|
+
### **QiitaPicks**
|
36
|
+
|
37
|
+
```zsh
|
38
|
+
% gem install qiita_picks
|
39
|
+
```
|
40
|
+
|
41
|
+
### **wkhtmltopdf**
|
42
|
+
|
43
|
+
1. Install by hand (recommended):
|
44
|
+
|
45
|
+
<https://github.com/pdfkit/pdfkit/wiki/Installing-WKHTMLTOPDF>
|
46
|
+
|
47
|
+
2. Try using the `wkhtmltopdf-binary` gem (mac + linux i386)
|
48
|
+
```
|
49
|
+
gem install wkhtmltopdf-binary
|
50
|
+
```
|
51
|
+
*Note:* The automated installer has been removed.
|
52
|
+
|
53
|
+
## Getting Started
|
54
|
+
|
55
|
+
### **BASIC**
|
56
|
+
|
57
|
+
```zsh
|
58
|
+
# 指定したURLの記事をまとめる (カンマ区切り)
|
59
|
+
% qiita_picks <URLs>
|
60
|
+
|
61
|
+
# 特定ユーザーの記事をまとめる
|
62
|
+
% qiita_picks list_user_items -u <username> -a <access_token>
|
63
|
+
|
64
|
+
# 特定ユーザーがストックした記事をまとめる
|
65
|
+
% qiita_picks list_user_stocks -u <username> -a <access_token>
|
66
|
+
|
67
|
+
# 特定のタグに関連する記事をまとめる
|
68
|
+
% qiita_picks list_tag_items -t <tag> -a <access_token>
|
69
|
+
|
70
|
+
# 『先週ストックが多かった投稿ベスト20』メールに掲載された記事をまとめる
|
71
|
+
% qiita_picks email_weekly_popular -e <email> -p <password>
|
72
|
+
|
73
|
+
# 『今週Qiitaでストックした記事』メールに掲載された記事をまとめる
|
74
|
+
% qiita_picks email_weekly_stocked -e <email> -p <password>
|
75
|
+
|
76
|
+
# はてなブックマークにブックマークされた人気の記事をまとめる
|
77
|
+
% qiita_picks list_hatena_popular -t <tag>
|
78
|
+
|
79
|
+
# はてなブックマークにブックマークされた新着の記事をまとめる
|
80
|
+
% qiita_picks list_hatena_recent -t <tag>
|
81
|
+
```
|
82
|
+
|
83
|
+
タグ・ユーザ名での記事の取得時に、Qiita Developer APIを利用しています。
|
84
|
+
事前にアカウントとアクセストークンを取得してください。
|
85
|
+
|
86
|
+
[新しくトークンを発行する](https://qiita.com/settings/tokens/new)
|
87
|
+
|
88
|
+
### **ADVANCED**
|
89
|
+
|
90
|
+
生成したPDFをメールに添付すると、デバイスを選ばずに、
|
91
|
+
いつでもオフラインで学習できるので、プログラマー生活がより快適になります。
|
92
|
+
|
93
|
+
それぞれのコマンドで生成したPDFを送信する場合は、`-e <email>` と `-p <password>` のオプションを設定してください。
|
94
|
+
|
95
|
+
:warning: **メールの送受信は共に、指定したGmailアカウントから実行されます**
|
96
|
+
|
97
|
+
```zsh
|
98
|
+
# 指定したURLの記事をまとめる (カンマ区切り) + メール送信
|
99
|
+
% qiita_picks <URLs> -e <email> -p <password>
|
100
|
+
```
|
101
|
+
|
102
|
+
なお、`email_weekly_popular`と`email_weekly_stocked`コマンドについては、
|
103
|
+
別途、`-s <send_mail_flag>`を渡す必要があります。
|
104
|
+
|
105
|
+
```zsh
|
106
|
+
# 『先週ストックが多かった投稿ベスト20』メールに掲載された記事 + メール送信
|
107
|
+
% qiita_picks email_weekly_popular -e <email> -p <password> -s true
|
108
|
+
```
|
109
|
+
|
110
|
+
特殊な処理がしたい場合は、以下を参考にご自由にどうぞ。
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
require 'qiita_picks'
|
114
|
+
|
115
|
+
url = %w{http://qiita.com/baba_s/items/c8d25456c0ee4ef52f94 http://qiita.com/y_minowa/items/f12aabbae7b0048cfe64}
|
116
|
+
generator = QiitaPicks::Generator.new(email, password, access_token)
|
117
|
+
|
118
|
+
# 指定したURLの記事をまとめる
|
119
|
+
generator.generate_from_url(url)
|
120
|
+
|
121
|
+
# 指定したURLの記事をまとめて 自身のGmailアカウントに送信
|
122
|
+
generator.generate_from_url(url, deliver: true)
|
123
|
+
```
|
124
|
+
|
125
|
+
### **TIPS**
|
126
|
+
|
127
|
+
#### クラウドサービスにアップロード
|
128
|
+
|
129
|
+
ローカルにある、Dropbox等の**クラウドサービスと同期するフォルダに向けて生成**するのが、最もラクかと思います。メールで送りたくない場合は、お試しください。
|
130
|
+
|
131
|
+
#### JenkinsやCronで定期的に自動生成
|
132
|
+
|
133
|
+
`qiita_picks`コマンドを定期的に実行するようスケジューリングすると、インプットが捗ります。下記のリンクを参考に設定してみてはいかがでしょうか。
|
134
|
+
|
135
|
+
- [cronに関する投稿 - Qiita](http://qiita.com/tags/cron)
|
136
|
+
- [OS XにJenkinsをHomebrewでセットアップする - Qiita](http://qiita.com/makoto_kw/items/cbe93d4ebbc35f3b43fd)
|
137
|
+
|
138
|
+
## Caution
|
139
|
+
|
140
|
+
- 作成したPDFを、インターネット上で公開・配布することはご遠慮ください。
|
141
|
+
- Qiita[キータ]へのアクセス負荷を考慮し、**節度のあるご利用**をお願いします。
|
142
|
+
- Qiita[キータ]は、Increments株式会社が提供するサービスです。当スクリプトは、Increments株式会社様による提供ではございませんので、何卒ご注意ください。
|
143
|
+
|
144
|
+
## Feedback
|
145
|
+
|
146
|
+
何かお気づきの点があれば、[こちらのフォーム](http://goo.gl/forms/PGFggwhCu1)よりご意見をお送りください :sunglasses:
|
147
|
+
|
148
|
+
## Contributing
|
149
|
+
|
150
|
+
不具合等ありましたら、お気軽にプルリクしてください。
|
151
|
+
|
152
|
+
1. Fork it ( https://github.com/henteco-labs/qiita_picks/fork )
|
153
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
154
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
155
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
156
|
+
5. Create a new Pull Request
|
157
|
+
|
158
|
+
## Copyright
|
159
|
+
|
160
|
+
Copyright © 2015 HentecoLabs Inc. See LICENSE.txt for further details.
|
data/Rakefile
ADDED
data/bin/qiita_picks
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
# external dependencies
|
5
|
+
require 'qiita_picks'
|
6
|
+
|
7
|
+
# stdlib dependencies
|
8
|
+
require 'optparse'
|
9
|
+
require 'uri'
|
10
|
+
|
11
|
+
opts = OptionParser.new do |opts|
|
12
|
+
opts.banner = <<-EOF
|
13
|
+
|
14
|
+
QiitaPicks - Qiitaに投稿された記事をまとめて PDFファイルを作成
|
15
|
+
|
16
|
+
EOF
|
17
|
+
opts.separator <<-EOF
|
18
|
+
Examples:
|
19
|
+
|
20
|
+
# 指定したURLの記事をまとめる (カンマ区切り)
|
21
|
+
% qiita_picks <URLs>
|
22
|
+
|
23
|
+
# 特定ユーザーの記事をまとめる
|
24
|
+
% qiita_picks list_user_items -u <username> -a <access_token>
|
25
|
+
|
26
|
+
# 特定ユーザーがストックした記事をまとめる
|
27
|
+
% qiita_picks list_user_stocks -u <username> -a <access_token>
|
28
|
+
|
29
|
+
# 特定のタグに関連する記事をまとめる
|
30
|
+
% qiita_picks list_tag_items -t <tag> -a <access_token>
|
31
|
+
|
32
|
+
# 『先週ストックが多かった投稿ベスト20』メールに掲載された記事をまとめる
|
33
|
+
% qiita_picks email_weekly_popular -e <email> -p <password>
|
34
|
+
|
35
|
+
# 『今週Qiitaでストックした記事』メールに掲載された記事をまとめる
|
36
|
+
% qiita_picks email_weekly_stocked -e <email> -p <password>
|
37
|
+
|
38
|
+
# はてなブックマークにブックマークされた人気の記事をまとめる
|
39
|
+
% qiita_picks list_hatena_popular -t <tag>
|
40
|
+
|
41
|
+
# はてなブックマークにブックマークされた新着の記事をまとめる
|
42
|
+
% qiita_picks list_hatena_recent -t <tag>
|
43
|
+
|
44
|
+
Options:
|
45
|
+
|
46
|
+
EOF
|
47
|
+
|
48
|
+
opts.on("-a", "--access_token [access_token]", "AccessToken @ Qiita") do |access_token|
|
49
|
+
@access_token = access_token.strip
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on("-e", "--email [email]", "Email (Gmail)") do |email|
|
53
|
+
@email = email.strip
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on("-p", "--password [password]", "Password (Gmail)") do |password|
|
57
|
+
@password = password.strip
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on("-s", "--send_mail_flag [send_mail_flag]", "Send email flag <boolean>") do |v|
|
61
|
+
@send_mail = ( v == "true" )
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.on("-t", "--tag [tag]", "Tag") do |tag|
|
65
|
+
@tag = tag.strip
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on("-u", "--username [username]", "UserName") do |username|
|
69
|
+
@username = username.strip
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on_tail("-?", "--help", "Show this message") do
|
73
|
+
puts opts
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
|
77
|
+
opts.on_tail("-v", "--version", "Show version") do
|
78
|
+
puts "version #{QiitaPicks::VERSION} on Ruby #{RUBY_VERSION}"
|
79
|
+
exit
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.parse!
|
84
|
+
|
85
|
+
command = ARGV.shift
|
86
|
+
|
87
|
+
if command.to_s.strip.empty?
|
88
|
+
puts opts
|
89
|
+
exit 1
|
90
|
+
end
|
91
|
+
|
92
|
+
unless QiitaPicks.wkhtmltopdf_installed?
|
93
|
+
puts <<-EOF
|
94
|
+
[ERROR] wkhtmltopdf not found"
|
95
|
+
See at: http://wkhtmltopdf.org/downloads.html
|
96
|
+
EOF
|
97
|
+
exit 1
|
98
|
+
end
|
99
|
+
|
100
|
+
begin
|
101
|
+
generator = QiitaPicks::Generator.new(email: @email, password: @password, access_token: @access_token)
|
102
|
+
@send_mail ||= false
|
103
|
+
|
104
|
+
case command
|
105
|
+
when 'list_user_items'
|
106
|
+
generator.generate_from_list_user_items(@username, deliver: [@email, @password].none?(&:nil?))
|
107
|
+
exit
|
108
|
+
when 'list_user_stocks'
|
109
|
+
generator.generate_from_list_user_stocks(@username, deliver: [@email, @password].none?(&:nil?))
|
110
|
+
exit
|
111
|
+
when 'list_tag_items'
|
112
|
+
generator.generate_from_list_tag_items(@tag, deliver: [@email, @password].none?(&:nil?))
|
113
|
+
exit
|
114
|
+
when 'list_hatena_popular'
|
115
|
+
generator.generate_from_list_hatebu_popular(tag: @tag, deliver: [@email, @password].none?(&:nil?))
|
116
|
+
exit
|
117
|
+
when 'list_hatena_recent'
|
118
|
+
generator.generate_from_list_hatebu_recent(tag: @tag, deliver: [@email, @password].none?(&:nil?))
|
119
|
+
exit
|
120
|
+
when 'email_weekly_popular'
|
121
|
+
generator.generate_from_email_weekly_popular(deliver: @send_mail)
|
122
|
+
exit
|
123
|
+
when 'email_weekly_stocked'
|
124
|
+
generator.generate_from_email_weekly_stocked(deliver: @send_mail)
|
125
|
+
exit
|
126
|
+
when /^https*\:\/\/.+/
|
127
|
+
urls = command.split(",").map(&:strip)
|
128
|
+
generator.generate_from_url(urls, deliver: [@email, @password].none?(&:nil?))
|
129
|
+
exit
|
130
|
+
else
|
131
|
+
puts opts
|
132
|
+
exit 1
|
133
|
+
end
|
134
|
+
rescue => e
|
135
|
+
puts "[ERROR] #{e.class} - #{e.message}"
|
136
|
+
exit 1
|
137
|
+
end
|
data/lib/qiita_picks.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "qiita_picks/version"
|
2
|
+
require "qiita_picks/generator"
|
3
|
+
require "qiita_picks/mailer"
|
4
|
+
require "qiita_picks/picker"
|
5
|
+
|
6
|
+
module QiitaPicks
|
7
|
+
FILE_BASENAME_DEFAULT = "%Y%m%d%H%M_qiita_picks"
|
8
|
+
FILE_BASENAME_EMAIL_WEEKLY_POPULAR = "%Y%m%d_email_weekly_popular"
|
9
|
+
FILE_BASENAME_EMAIL_WEEKLY_STOCKED = "%Y%m%d_email_weekly_stocked"
|
10
|
+
FILE_BASENAME_LIST_TAG_ITEMS = "%Y%m%d%H%M_list_tag_items"
|
11
|
+
FILE_BASENAME_LIST_USER_ITEMS = "%Y%m%d%H%M_list_user_items"
|
12
|
+
FILE_BASENAME_LIST_USER_STOCKS = "%Y%m%d%H%M_list_user_stocks"
|
13
|
+
FILE_BASENAME_LIST_HATEBU_POPULAR = "%Y%m%d%H%M_list_hatebu_popular"
|
14
|
+
FILE_BASENAME_LIST_HATEBU_RECENT = "%Y%m%d%H%M_list_hatebu_recent"
|
15
|
+
|
16
|
+
EMAIL_SUBJECT_DEFAULT = "[QiitaPicks] Qiitaの記事まとめ - %Y/%m/%d"
|
17
|
+
EMAIL_SUBJECT_EMAIL_WEEKLY_POPULAR = "[QiitaPicks] Qiitaでストックが多かった投稿 - %Y/%m/%d 配信"
|
18
|
+
EMAIL_SUBJECT_EMAIL_WEEKLY_STOCKED = "[QiitaPicks] <SUBJECT> - %Y/%m/%d 配信"
|
19
|
+
EMAIL_SUBJECT_LIST_TAG_ITEMS = "[QiitaPicks] <TAG>に関するQiitaの記事まとめ - %Y/%m/%d"
|
20
|
+
EMAIL_SUBJECT_LIST_USER_ITEMS = "[QiitaPicks] <USERNAME>に関するQiitaの記事まとめ - %Y/%m/%d"
|
21
|
+
EMAIL_SUBJECT_LIST_USER_STOCKS = "[QiitaPicks] <USERNAME>がストックしたQiitaの記事まとめ - %Y/%m/%d"
|
22
|
+
EMAIL_SUBJECT_LIST_HATEBU_POPULAR = "[QiitaPicks] はてブで人気のQiitaの記事まとめ - %Y/%m/%d"
|
23
|
+
EMAIL_SUBJECT_LIST_HATEBU_RECENT = "[QiitaPicks] はてブで新着のQiitaの記事まとめ - %Y/%m/%d"
|
24
|
+
|
25
|
+
REPOSITORY_URL = "https://github.com/henteco-labs/qiita_picks"
|
26
|
+
REPOSITORY_URL_SHORTEN = "http://goo.gl/QUkuEY"
|
27
|
+
FEEDBACK_URL_SHORTEN = "http://goo.gl/forms/PGFggwhCu1"
|
28
|
+
|
29
|
+
EMAIL_CONTENT_DEFAULT = <<-EOF
|
30
|
+
Generated by QiitaPicks version #{QiitaPicks::VERSION} on Ruby #{RUBY_VERSION}
|
31
|
+
GitHub: #{QiitaPicks::REPOSITORY_URL_SHORTEN}
|
32
|
+
|
33
|
+
Please send me your feedback:)
|
34
|
+
#{QiitaPicks::FEEDBACK_URL_SHORTEN}
|
35
|
+
EOF
|
36
|
+
HTML_FOOTER_CREDIT = <<-EOF
|
37
|
+
<footer>
|
38
|
+
<p>Generated by QiitaPicks version #{QiitaPicks::VERSION} on Ruby #{RUBY_VERSION}</p>
|
39
|
+
<p>GitHub: <a href="#{QiitaPicks::REPOSITORY_URL_SHORTEN}">#{QiitaPicks::REPOSITORY_URL}</a></p>
|
40
|
+
<p>Please send me your feedback:)</p>
|
41
|
+
<p><a href="#{QiitaPicks::FEEDBACK_URL_SHORTEN}">#{QiitaPicks::FEEDBACK_URL_SHORTEN}</a></p>
|
42
|
+
</footer>
|
43
|
+
EOF
|
44
|
+
|
45
|
+
def self.wkhtmltopdf_installed?
|
46
|
+
/^\// =~ `which wkhtmltopdf`.to_s
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# external dependencies
|
2
|
+
require 'qiita'
|
3
|
+
|
4
|
+
# stdlib dependencies
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
module QiitaPicks
|
8
|
+
class Generator
|
9
|
+
def initialize(params={})
|
10
|
+
params[:email] ||= ''
|
11
|
+
params[:password] ||= ''
|
12
|
+
params[:access_token] ||= ''
|
13
|
+
@email = params[:email]
|
14
|
+
@mailer = QiitaPicks::Mailer.new(params[:email], params[:password])
|
15
|
+
@qiita = Qiita::Client.new(access_token: params[:access_token])
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_from_url(url=[], opts={})
|
19
|
+
opts[:deliver] ||= false
|
20
|
+
opts[:deliver] ? generate_and_deliver(url: url) : generate(url: url)
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_from_email_weekly_popular(opts={})
|
24
|
+
opts[:limit] ||= 1
|
25
|
+
opts[:deliver] ||= false
|
26
|
+
@mailer.weekly_popular(opts[:limit]).each do |mail|
|
27
|
+
@basename = mail[:date].strftime QiitaPicks::FILE_BASENAME_EMAIL_WEEKLY_POPULAR
|
28
|
+
@subject = mail[:date].strftime QiitaPicks::EMAIL_SUBJECT_EMAIL_WEEKLY_POPULAR
|
29
|
+
opts[:deliver] ? generate_and_deliver(url: mail[:url]) : generate(url: mail[:url])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate_from_email_weekly_stocked(opts={})
|
34
|
+
opts[:limit] ||= 1
|
35
|
+
opts[:deliver] ||= false
|
36
|
+
@mailer.weekly_stocked(opts[:limit]).each do |mail|
|
37
|
+
@basename = mail[:date].strftime QiitaPicks::FILE_BASENAME_EMAIL_WEEKLY_STOCKED
|
38
|
+
@subject = mail[:date].strftime(QiitaPicks::EMAIL_SUBJECT_EMAIL_WEEKLY_STOCKED).gsub(/<SUBJECT>/, mail[:subject])
|
39
|
+
opts[:deliver] ? generate_and_deliver(url: mail[:url]) : generate(url: mail[:url])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate_from_list_tag_items(tag, opts={})
|
44
|
+
opts[:page] ||= 1
|
45
|
+
opts[:per_page] ||= 20
|
46
|
+
opts[:deliver] ||= false
|
47
|
+
@basename = Time.now.strftime QiitaPicks::FILE_BASENAME_LIST_TAG_ITEMS
|
48
|
+
@subject = Time.now.strftime(QiitaPicks::EMAIL_SUBJECT_LIST_TAG_ITEMS).gsub(/<TAG>/, tag.capitalize)
|
49
|
+
items = @qiita.list_tag_items(tag, page: opts[:page], per_page: opts[:per_page]).body
|
50
|
+
opts[:deliver] ? generate_and_deliver(items: items) : generate(items: items)
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate_from_list_user_items(username, opts={})
|
54
|
+
opts[:page] ||= 1
|
55
|
+
opts[:per_page] ||= 20
|
56
|
+
opts[:deliver] ||= false
|
57
|
+
@basename = Time.now.strftime QiitaPicks::FILE_BASENAME_LIST_USER_ITEMS
|
58
|
+
@subject = Time.now.strftime(QiitaPicks::EMAIL_SUBJECT_LIST_USER_ITEMS).gsub(/<USERNAME>/, username)
|
59
|
+
items = @qiita.list_user_items(username, page: opts[:page], per_page: opts[:per_page]).body
|
60
|
+
opts[:deliver] ? generate_and_deliver(items: items) : generate(items: items)
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_from_list_user_stocks(username, opts={})
|
64
|
+
opts[:page] ||= 1
|
65
|
+
opts[:per_page] ||= 20
|
66
|
+
opts[:deliver] ||= false
|
67
|
+
@basename = Time.now.strftime QiitaPicks::FILE_BASENAME_LIST_USER_STOCKS
|
68
|
+
@subject = Time.now.strftime(QiitaPicks::EMAIL_SUBJECT_LIST_USER_STOCKS).gsub(/<USERNAME>/, username)
|
69
|
+
items = @qiita.list_user_stocks(username, page: opts[:page], per_page: opts[:per_page]).body
|
70
|
+
opts[:deliver] ? generate_and_deliver(items: items) : generate(items: items)
|
71
|
+
end
|
72
|
+
|
73
|
+
def generate_from_list_hatebu_popular(opts={})
|
74
|
+
opts[:deliver] ||= false
|
75
|
+
@basename = Time.now.strftime QiitaPicks::FILE_BASENAME_LIST_HATEBU_POPULAR
|
76
|
+
@subject = Time.now.strftime QiitaPicks::EMAIL_SUBJECT_LIST_HATEBU_POPULAR
|
77
|
+
url = QiitaPicks::Picker.hatebu_bookmark_url opts[:tag], :popular
|
78
|
+
opts[:deliver] ? generate_and_deliver(url: url) : generate(url: url)
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_from_list_hatebu_recent(opts={})
|
82
|
+
opts[:deliver] ||= false
|
83
|
+
@basename = Time.now.strftime QiitaPicks::FILE_BASENAME_LIST_HATEBU_RECENT
|
84
|
+
@subject = Time.now.strftime QiitaPicks::EMAIL_SUBJECT_LIST_HATEBU_RECENT
|
85
|
+
url = QiitaPicks::Picker.hatebu_bookmark_url opts[:tag], :recent
|
86
|
+
opts[:deliver] ? generate_and_deliver(url: url) : generate(url: url)
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def generate(params={})
|
92
|
+
params[:url] ||= []
|
93
|
+
params[:items] ||= []
|
94
|
+
params[:dest] ||= '.'
|
95
|
+
@basename ||= Time.now.strftime QiitaPicks::FILE_BASENAME_DEFAULT
|
96
|
+
@subject ||= Time.now.strftime QiitaPicks::EMAIL_SUBJECT_DEFAULT
|
97
|
+
@picker = QiitaPicks::Picker.new
|
98
|
+
@picker.build_html_from_url(params[:url], @subject)
|
99
|
+
@picker.build_html_from_items(params[:items], @subject)
|
100
|
+
@picker.save_as_pdf(dest: params[:dest], basename: @basename)
|
101
|
+
@picker.save_as_html(dest: params[:dest], basename: @basename)
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_and_deliver(params={})
|
105
|
+
Dir.mktmpdir do |dir|
|
106
|
+
generate params.merge({dest: dir})
|
107
|
+
@mailer.deliver(
|
108
|
+
to: @email,
|
109
|
+
subject: @subject,
|
110
|
+
body: QiitaPicks::EMAIL_CONTENT_DEFAULT,
|
111
|
+
add_files: [@picker.path_to_pdf, @picker.path_to_html]
|
112
|
+
)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# external dependencies
|
2
|
+
require 'gmail'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
# stdlib dependencies
|
6
|
+
require 'nkf'
|
7
|
+
|
8
|
+
module QiitaPicks
|
9
|
+
class Mailer
|
10
|
+
def initialize(email, password)
|
11
|
+
@gmail = Gmail.new(email, password)
|
12
|
+
end
|
13
|
+
|
14
|
+
def deliver(params={})
|
15
|
+
return if params[:add_files].compact.empty?
|
16
|
+
@gmail.deliver {
|
17
|
+
to params[:to]
|
18
|
+
subject params[:subject]
|
19
|
+
body params[:body]
|
20
|
+
params[:add_files].each {|f| add_file(f)}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def weekly_popular(limit=5)
|
25
|
+
@gmail.inbox.emails(:unread, from: "info@qiita.com").last(limit).inject([]) do |data, mail|
|
26
|
+
url = mail.text_part.decoded.scan(/^\d+位.+\((http.+?)\)/).flatten
|
27
|
+
data << Hash[:subject, mail.subject, :date, mail.date, :url, url]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def weekly_stocked(limit=5)
|
32
|
+
@gmail.inbox.emails(:unread, from: "noreply@qiita.com").last(limit).inject([]) do |data, mail|
|
33
|
+
next unless /^.+?さんが今週Qiitaでストックした記事$/ =~ mail.subject
|
34
|
+
doc = Nokogiri::HTML NKF.nkf('-w', NKF.nkf('-w', mail.body.decoded))
|
35
|
+
url = doc.css('.stockedArticlesTable a').inject([]){|list, elem|
|
36
|
+
list << elem.attr("href").match(/(^http.+?)\?/)[1]
|
37
|
+
}.uniq
|
38
|
+
data << Hash[:subject, mail.subject, :date, mail.date, :url, url]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# external dependencies
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'pdfkit'
|
4
|
+
require 'baby_erubis'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext'
|
7
|
+
|
8
|
+
# stdlib dependencies
|
9
|
+
require 'date'
|
10
|
+
require 'nkf'
|
11
|
+
require 'uri'
|
12
|
+
require 'open-uri'
|
13
|
+
require 'net/http'
|
14
|
+
|
15
|
+
module QiitaPicks
|
16
|
+
class Picker
|
17
|
+
ERB_TEMPLATE_ARTICLE = File.expand_path '../templates/article.erb', __FILE__
|
18
|
+
ERB_TEMPLATE_LAYOUT = File.expand_path '../templates/layout.erb', __FILE__
|
19
|
+
PDFKIT_OPTIONS = {
|
20
|
+
encoding: 'UTF-8',
|
21
|
+
page_size: 'A4',
|
22
|
+
quiet: false,
|
23
|
+
no_background: false
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
attr_reader :path_to_pdf, :path_to_html
|
27
|
+
|
28
|
+
def self.hatebu_bookmark_url(tag=nil, sort=:popular)
|
29
|
+
uri = URI('http://b.hatena.ne.jp/search/text')
|
30
|
+
uri.query = {
|
31
|
+
q: ['http://qiita.com/', tag].compact.join(' '),
|
32
|
+
date_begin: (Time.now - 60*60*24*30).strftime('%Y-%m-%d'),
|
33
|
+
date_end: Time.now.strftime('%Y-%m-%d'),
|
34
|
+
users: 3,
|
35
|
+
sort: sort,
|
36
|
+
safe: 'off',
|
37
|
+
mode: 'rss'
|
38
|
+
}.to_param
|
39
|
+
doc = Nokogiri::XML open(uri.to_s)
|
40
|
+
doc.xpath("//rdf:Seq/rdf:li").map{|x| x.attr("rdf:resource")}
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_html_from_url(url=[], title=nil)
|
44
|
+
return if url.empty?
|
45
|
+
@title = title || Time.now.strftime(QiitaPicks::EMAIL_SUBJECT_DEFAULT)
|
46
|
+
@contents ||= build_articles_from_url url
|
47
|
+
@html ||= html
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_html_from_items(items=[], title=nil)
|
51
|
+
return if items.empty?
|
52
|
+
@title = title || Time.now.strftime(QiitaPicks::EMAIL_SUBJECT_DEFAULT)
|
53
|
+
@contents ||= build_articles_from_items items
|
54
|
+
@html ||= html
|
55
|
+
end
|
56
|
+
|
57
|
+
def save_as_pdf(opts={})
|
58
|
+
return if @html.nil?
|
59
|
+
opts[:dest] ||= '.'
|
60
|
+
opts[:basename] ||= Time.now.strftime QiitaPicks::FILE_BASENAME_DEFAULT
|
61
|
+
opts[:pdf_options] ||= {}
|
62
|
+
@path_to_pdf = File.join(opts[:dest], "#{opts[:basename]}.pdf")
|
63
|
+
PDFKit.new(@html, PDFKIT_OPTIONS.merge(opts[:pdf_options])).to_file @path_to_pdf
|
64
|
+
puts "[GENERATE] #{@path_to_pdf}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def save_as_html(opts={})
|
68
|
+
return if @html.nil?
|
69
|
+
opts[:dest] ||= '.'
|
70
|
+
opts[:basename] ||= Time.now.strftime QiitaPicks::FILE_BASENAME_DEFAULT
|
71
|
+
@path_to_html = File.join(opts[:dest], "#{opts[:basename]}.html")
|
72
|
+
open(@path_to_html, "w+") {|f| f.write @html}
|
73
|
+
puts "[GENERATE] #{@path_to_html}"
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def html
|
79
|
+
return if @contents.empty?
|
80
|
+
template = BabyErubis::Html.new.from_file(ERB_TEMPLATE_LAYOUT, 'utf-8')
|
81
|
+
template.render(title: @title, contents: @contents, credit: HTML_FOOTER_CREDIT)
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_articles_from_url(urls=[])
|
85
|
+
urls.select {|url| /qiita/ =~ URI.parse(url).host}.uniq.inject('') {|articles, url|
|
86
|
+
if res = fetch(url)
|
87
|
+
uri = res.uri
|
88
|
+
doc = Nokogiri::HTML NKF.nkf('-w', res.body)
|
89
|
+
template = BabyErubis::Html.new.from_file(ERB_TEMPLATE_ARTICLE, 'utf-8')
|
90
|
+
context = {
|
91
|
+
url: "#{uri.scheme}://#{uri.host}#{uri.path}",
|
92
|
+
title: doc.css('title').text,
|
93
|
+
content: doc.css('.markdownContent').inner_html,
|
94
|
+
user_name: doc.css('.itemsShowAuthorInfo_userName').text,
|
95
|
+
created_at: doc.css('ul.itemsShowHeaderTitle_status time').first.text
|
96
|
+
}
|
97
|
+
articles << template.render(context)
|
98
|
+
end
|
99
|
+
articles
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def build_articles_from_items(items=[])
|
104
|
+
items.inject('') {|articles, item|
|
105
|
+
template = BabyErubis::Html.new.from_file(ERB_TEMPLATE_ARTICLE, 'utf-8')
|
106
|
+
context = {
|
107
|
+
url: item['url'],
|
108
|
+
title: item['title'],
|
109
|
+
content: item['rendered_body'],
|
110
|
+
user_name: item['user']['id'],
|
111
|
+
created_at: DateTime.parse(item['created_at']).strftime('%Y/%m/%d')
|
112
|
+
}
|
113
|
+
articles << template.render(context)
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def fetch(url, limit=10)
|
118
|
+
res = Net::HTTP.get_response URI.parse(url)
|
119
|
+
puts "[#{res.code} #{res.message}] #{url}"
|
120
|
+
case res
|
121
|
+
when Net::HTTPSuccess
|
122
|
+
return res
|
123
|
+
when Net::HTTPRedirection
|
124
|
+
return fetch(res['location'], limit - 1)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<header>
|
2
|
+
<h1><%= @title %></h1>
|
3
|
+
<p>Posted by: <%= @user_name %> | Created at: <%= @created_at %> | <a href="<%= @url %>">Permalink</a></p>
|
4
|
+
</header>
|
5
|
+
<section class="markdownContent markdownContent-headingEnabled"><%== @content %></section>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="ja">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
|
6
|
+
<meta name="generator" content="QiitaPicks" />
|
7
|
+
<title><%= @title %></title>
|
8
|
+
<style type="text/css" media="all">body{font-size:11pt!important;background-color:#fff;color:#000;font-family:"Helvetica Neue",Helvetica,"游ゴシック",YuGothic,"ヒラギノ角ゴ ProN W3","Hiragino Kaku Gothic ProN",sans-serif;-webkit-font-smoothing:antialiased!important}a{color:#337ab7;text-decoration:underline}header{padding:.5em 0;border-bottom:.2em solid #79b74a;page-break-before:always}header:first-child{page-break-before:avoid}header h1{margin:0;color:#79b74a;font-size:19pt!important}header p{margin:.5em 0 0 0;color:#999;font-size:9pt!important;text-align:right}section{padding-top:2em}.hidden{display:none}.markdownContent>:first-child{margin-top:0!important}.markdownContent-headingEnabled h1,.markdownContent-headingEnabled h2,.markdownContent-headingEnabled h3,.markdownContent-headingEnabled h4,.markdownContent-headingEnabled h5,.markdownContent-headingEnabled h6{position:relative}.markdownContent blockquote{font-size:11pt;margin-top:1em;margin-bottom:1em;margin-left:.8em;padding:.8em;color:#555;border-left:solid 4px #ddd}.markdownContent blockquote>:first-child{margin-top:0}.markdownContent blockquote h1,.markdownContent blockquote h2,.markdownContent blockquote h3,.markdownContent blockquote h4,.markdownContent blockquote h5,.markdownContent blockquote h6{color:#555}.markdownContent a{word-wrap:break-word;word-break:break-all}.markdownContent hr{height:2px;margin:1em 0;border:0;background-color:#ccc}.markdownContent em{font-family:"Helvetica Neue",Helvetica,"ヒラギノ角ゴ ProN W3","Hiragino Kaku Gothic ProN","游ゴシック",YuGothic,sans-serif;font-style:italic}.markdownContent b,.markdownContent ins,.markdownContent strong{font-weight:900}.markdownContent del{text-decoration:line-through}.markdownContent p{font-size:11pt;line-height:1.7;margin:1em 0;word-wrap:break-word}.markdownContent img{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;max-width:100%;margin:0;vertical-align:middle}.markdownContent dl{margin:1em 0}.markdownContent dl dd{margin-left:2em}.markdownContent table{margin:1em 0;border-top:solid 1px #d9d9d9;border-left:solid 1px #d9d9d9}.markdownContent td,.markdownContent th{padding:8px 10px;word-wrap:break-word;border-right:solid 1px #ccc;border-bottom:solid 1px #ccc}.markdownContent th,.markdownContent thead td{font-weight:900;background-color:#fff}.markdownContent tbody tr:nth-child(odd){background-color:rgba(0,0,0,.03)}.markdownContent li p:first-child{margin:0}.markdownContent ol,.markdownContent ul{line-height:1.7;margin-top:1em;margin-bottom:1em;padding-left:1.5em}.markdownContent ol>li{list-style-type:decimal}.markdownContent ul>li{list-style-type:disc}.markdownContent li>ol,.markdownContent li>ul{margin-top:0;margin-bottom:0}.markdownContent h1,.markdownContent h2,.markdownContent h3,.markdownContent h4,.markdownContent h5,.markdownContent h6{font-size:11pt;font-family:sans-serif;line-height:1.4;margin:1.35em 0 .7em}.markdownContent h1{line-height:1.2;padding-bottom:.3em;border-bottom:2px solid #dedede}.markdownContent h1 .emoji{width:1.05em;height:1.05em;vertical-align:top}.markdownContent h2{line-height:1.2;padding-bottom:.3em;border-bottom:1px dotted #ccc}.markdownContent h2 .emoji{width:1.08em;height:1.08em;vertical-align:top}.markdownContent h3{line-height:1.4;margin-top:1.4em}.markdownContent h4{margin-top:1.3em}.markdownContent h5{margin-top:1.5em}.markdownContent h6{margin-top:1.5em;color:#777}.markdownContent .code-frame{line-height:0;margin:1em 0;border-radius:3px;background-color:#f7f7f7}.markdownContent .code-frame pre{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;line-height:18px;margin:0;padding:8px 15px;white-space:pre-wrap;border:0;border-radius:3px;background-color:#f7f7f7}.markdownContent .code-lang{font-size:9pt;font-weight:400;line-height:1;display:inline-block;margin:0;padding:3px 6px;color:#555;background-color:rgba(0,0,0,.07)}.markdownContent .emoji{width:20px;height:20px}.markdownContent .fa.fa-link,.markdownContent .icon-link{font-size:16px;font-weight:400;position:absolute;top:50%;left:-28px;display:none;margin-top:-18px;padding:10px 5px 10px 10px;color:#555}.markdownContent .footnotes{font-size:.9em;margin-top:2em}.markdownContent .footnotes hr{display:none}.markdownContent .fragment{position:relative;top:-10px;display:block}.markdownContent .highlight{background:#fff}.markdownContent .highlight .c{font-style:italic;color:#998}.markdownContent .highlight .err{color:#a61717;background-color:#e3d2d2}.markdownContent .highlight .k,.markdownContent .highlight .o{font-weight:700}.markdownContent .highlight .cm{font-style:italic;color:#998}.markdownContent .highlight .cp{font-weight:700;color:#999}.markdownContent .highlight .c1{font-style:italic;color:#998}.markdownContent .highlight .cs{font-weight:700;font-style:italic;color:#999}.markdownContent .highlight .gd{color:#000;background-color:#fdd}.markdownContent .highlight .gd .x{color:#000;background-color:#faa}.markdownContent .highlight .ge{font-style:italic}.markdownContent .highlight .gr{color:#a00}.markdownContent .highlight .gh{color:#999}.markdownContent .highlight .gi{color:#000;background-color:#dfd}.markdownContent .highlight .gi .x{color:#000;background-color:#afa}.markdownContent .highlight .go{color:#888}.markdownContent .highlight .gp{color:#555}.markdownContent .highlight .gs{font-weight:700}.markdownContent .highlight .gu{font-weight:700;color:purple}.markdownContent .highlight .gt{color:#a00}.markdownContent .highlight .kc,.markdownContent .highlight .kd,.markdownContent .highlight .kn,.markdownContent .highlight .kp,.markdownContent .highlight .kr{font-weight:700}.markdownContent .highlight .kt{font-weight:700;color:#458}.markdownContent .highlight .m{color:#099}.markdownContent .highlight .s{color:#d14}.markdownContent .highlight .n{color:#333}.markdownContent .highlight .na{color:teal}.markdownContent .highlight .nb{color:#0086b3}.markdownContent .highlight .nc{font-weight:700;color:#458}.markdownContent .highlight .no{color:teal}.markdownContent .highlight .ni{color:purple}.markdownContent .highlight .ne,.markdownContent .highlight .nf{font-weight:700;color:#900}.markdownContent .highlight .nn{color:#555}.markdownContent .highlight .nt{color:navy}.markdownContent .highlight .nv{color:teal}.markdownContent .highlight .ow{font-weight:700}.markdownContent .highlight .w{color:#bbb}.markdownContent .highlight .mf,.markdownContent .highlight .mh,.markdownContent .highlight .mi,.markdownContent .highlight .mo{color:#099}.markdownContent .highlight .s2,.markdownContent .highlight .sb,.markdownContent .highlight .sc,.markdownContent .highlight .sd,.markdownContent .highlight .se,.markdownContent .highlight .sh,.markdownContent .highlight .si,.markdownContent .highlight .sx{color:#d14}.markdownContent .highlight .sr{color:#009926}.markdownContent .highlight .s1{color:#d14}.markdownContent .highlight .ss{color:#990073}.markdownContent .highlight .bp{color:#999}.markdownContent .highlight .vc,.markdownContent .highlight .vg,.markdownContent .highlight .vi{color:teal}.markdownContent .highlight .il{color:#099}.markdownContent .highlight .gc{color:#999;background-color:#eaf2f5}.markdownContent .MathJax img,.markdownContent .MathJax_Display img{border:0!important}.markdownContent .parenthesis li{list-style-type:none}.markdownContent .parenthesis li span{margin-right:.5em;margin-left:-1.5em}.markdownContent .task-list-item{list-style-type:none}.markdownContent .task-list-item-checkbox{margin:.4em .5em 0 -1.3em}.markdownContent .task-list-item-checkbox[disabled]{cursor:default}footer{margin:0;padding:1em 0 0 0;page-break-before:always}footer p {font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace}</style>
|
9
|
+
</head>
|
10
|
+
<body><%== @contents %><%== @credit %></body>
|
11
|
+
</html>
|
data/qiita_picks.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'qiita_picks/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "qiita_picks"
|
8
|
+
spec.version = QiitaPicks::VERSION
|
9
|
+
spec.authors = ["Yoshiyuki Hirano"]
|
10
|
+
spec.email = ["info@henteco-labs.com"]
|
11
|
+
spec.description = %q{Generate PDF/HTML from articles posted on qiita.com. Uses wkhtmltopdf on the back-end which renders HTML using Webkit.}
|
12
|
+
spec.summary = %q{Generate PDF/HTML from articles posted on qiita.com.}
|
13
|
+
spec.homepage = "https://github.com/henteco-labs/qiita_picks"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.post_install_message = <<-EOF
|
16
|
+
|
17
|
+
qiita_picks installed! To get started fast:
|
18
|
+
|
19
|
+
$ qiita_picks <URLs>
|
20
|
+
|
21
|
+
Or see the README.md at:
|
22
|
+
|
23
|
+
https://github.com/henteco-labs/qiita_picks
|
24
|
+
|
25
|
+
EOF
|
26
|
+
|
27
|
+
spec.add_dependency "nokogiri", "~> 1.6"
|
28
|
+
spec.add_dependency "pdfkit", "~> 0.6"
|
29
|
+
spec.add_dependency "ruby-gmail", "~> 0.3"
|
30
|
+
spec.add_dependency "qiita", "~> 1.1"
|
31
|
+
spec.add_dependency "activesupport", "~> 4.1"
|
32
|
+
spec.add_dependency "baby_erubis", "~> 2.0"
|
33
|
+
|
34
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
35
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
36
|
+
spec.add_development_dependency "rspec", "~> 0"
|
37
|
+
spec.add_development_dependency "pry", "~> 0"
|
38
|
+
|
39
|
+
spec.files = `git ls-files -z`.split("\x0")
|
40
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
41
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
42
|
+
spec.require_paths = ["lib"]
|
43
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: qiita_picks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yoshiyuki Hirano
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pdfkit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ruby-gmail
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: qiita
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activesupport
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: baby_erubis
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: bundler
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.7'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.7'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '10.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '10.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: Generate PDF/HTML from articles posted on qiita.com. Uses wkhtmltopdf
|
154
|
+
on the back-end which renders HTML using Webkit.
|
155
|
+
email:
|
156
|
+
- info@henteco-labs.com
|
157
|
+
executables:
|
158
|
+
- qiita_picks
|
159
|
+
extensions: []
|
160
|
+
extra_rdoc_files: []
|
161
|
+
files:
|
162
|
+
- ".gitignore"
|
163
|
+
- ".rspec"
|
164
|
+
- ".travis.yml"
|
165
|
+
- Gemfile
|
166
|
+
- LICENSE.txt
|
167
|
+
- README.md
|
168
|
+
- Rakefile
|
169
|
+
- bin/qiita_picks
|
170
|
+
- lib/qiita_picks.rb
|
171
|
+
- lib/qiita_picks/generator.rb
|
172
|
+
- lib/qiita_picks/mailer.rb
|
173
|
+
- lib/qiita_picks/picker.rb
|
174
|
+
- lib/qiita_picks/templates/article.erb
|
175
|
+
- lib/qiita_picks/templates/layout.erb
|
176
|
+
- lib/qiita_picks/version.rb
|
177
|
+
- qiita_picks.gemspec
|
178
|
+
- spec/qiita_picks_spec.rb
|
179
|
+
- spec/spec_helper.rb
|
180
|
+
homepage: https://github.com/henteco-labs/qiita_picks
|
181
|
+
licenses:
|
182
|
+
- MIT
|
183
|
+
metadata: {}
|
184
|
+
post_install_message: |2+
|
185
|
+
|
186
|
+
qiita_picks installed! To get started fast:
|
187
|
+
|
188
|
+
$ qiita_picks <URLs>
|
189
|
+
|
190
|
+
Or see the README.md at:
|
191
|
+
|
192
|
+
https://github.com/henteco-labs/qiita_picks
|
193
|
+
|
194
|
+
rdoc_options: []
|
195
|
+
require_paths:
|
196
|
+
- lib
|
197
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - ">="
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
207
|
+
requirements: []
|
208
|
+
rubyforge_project:
|
209
|
+
rubygems_version: 2.2.2
|
210
|
+
signing_key:
|
211
|
+
specification_version: 4
|
212
|
+
summary: Generate PDF/HTML from articles posted on qiita.com.
|
213
|
+
test_files:
|
214
|
+
- spec/qiita_picks_spec.rb
|
215
|
+
- spec/spec_helper.rb
|