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 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
@@ -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
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in qiita_picks.gemspec
4
+ gemspec
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
+ ![](https://s3-ap-northeast-1.amazonaws.com/hentecolabs/tty.gif)
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
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
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
@@ -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:&nbsp;<%= @user_name %>&nbsp;|&nbsp;Created at: <%= @created_at %>&nbsp;|&nbsp;<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>
@@ -0,0 +1,3 @@
1
+ module QiitaPicks
2
+ VERSION = "0.1.2"
3
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe QiitaPicks do
4
+ it 'has a version number' do
5
+ expect(QiitaPicks::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'qiita_picks'
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