qiita_matome 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +22 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +0 -0
  6. data/.travis.yml +8 -0
  7. data/CONTRIBUTING.md +44 -0
  8. data/Gemfile +13 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +210 -0
  11. data/Rakefile +8 -0
  12. data/bin/qiitam +34 -0
  13. data/lib/display.rb +10 -0
  14. data/lib/display/display_consts.rb +35 -0
  15. data/lib/display/displayer.rb +81 -0
  16. data/lib/file_writer.rb +19 -0
  17. data/lib/models/article.rb +38 -0
  18. data/lib/models/articles.rb +40 -0
  19. data/lib/qiita_json_loader.rb +43 -0
  20. data/lib/qiita_matome/version.rb +4 -0
  21. data/lib/qiita_matome_core.rb +121 -0
  22. data/lib/qiita_matome_dsl.rb +31 -0
  23. data/lib/qiita_matome_dsl_model.rb +37 -0
  24. data/lib/sort.rb +10 -0
  25. data/lib/sort/sort_consts.rb +28 -0
  26. data/lib/sort/sorter.rb +51 -0
  27. data/lib/validators.rb +13 -0
  28. data/lib/validators/article_validator.rb +19 -0
  29. data/lib/validators/articles_validator.rb +16 -0
  30. data/lib/validators/display_columns_validator.rb +41 -0
  31. data/lib/validators/sort_type_validator.rb +19 -0
  32. data/manual_test_docs/.gitkeep +0 -0
  33. data/qiita_matome.gemspec +28 -0
  34. data/samples/matome_title_asc.md +25 -0
  35. data/spec/display/displayer_spec.rb +341 -0
  36. data/spec/file_writer_spec.rb +92 -0
  37. data/spec/models/article_spec.rb +131 -0
  38. data/spec/models/articles_spec.rb +305 -0
  39. data/spec/qiita_matome_core_spec.rb +46 -0
  40. data/spec/sort/sorter_spec.rb +392 -0
  41. data/spec/spec_helper.rb +16 -0
  42. data/spec/validators/article_validator_spec.rb +53 -0
  43. data/spec/validators/articles_validator_spec.rb +54 -0
  44. data/spec/validators/display_columns_validator_spec.rb +58 -0
  45. data/spec/validators/sort_type_validator_spec.rb +54 -0
  46. metadata +202 -0
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module QiitaMatome
4
+ # QiitaMatome::Validators
5
+ module Validators
6
+ # ArticleValidator
7
+ class ArticleValidator
8
+ ARTICLE_CLASS_ERROR = "invalid argument class '%s'.article must be Array"
9
+
10
+ def self.validate(articles)
11
+ return if articles.empty?
12
+ articles.each do |article|
13
+ next if article.is_a?(Article)
14
+ fail ArgumentError, format(ARTICLE_CLASS_ERROR, article.class)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ module QiitaMatome
4
+ # QiitaMatome::Validators
5
+ module Validators
6
+ # ArticlesValidator
7
+ class ArticlesValidator
8
+ ARTICLES_CLASS_ERROR = "invalid argument class '%s'. articles must be Array" # rubocop:disable LineLength
9
+
10
+ def self.validate(articles)
11
+ return if articles.is_a?(Array)
12
+ fail ArgumentError, format(ARTICLES_CLASS_ERROR, articles.class)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require 'display/display_consts'
3
+
4
+ module QiitaMatome
5
+ # QiitaMatome::Validators
6
+ module Validators
7
+ # DisplayColumnsValidator
8
+ class DisplayColumnsValidator
9
+ # rubocop:disable LineLength
10
+ DISPLAY_COLUMNS_TO_SYM_ERROR = "Invalid display_columns. Display_columns's class must be implement 'to_sym' method."
11
+ DISPLAY_COLUMNS_ERROR = "Invalid display_columns '%s'. Display_columns must be :title, :created_at, :updated_at, :stock_count or :no"
12
+ # rubocop:enable LineLength
13
+ DCC = Display::Consts::COLUMNS
14
+
15
+ class << self
16
+ def validate(display_columns)
17
+ display_columns.each do |display_column|
18
+ validate_each(display_column)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def validate_each(display_column)
25
+ validate_to_sym(display_column)
26
+ validate_display_column(display_column.to_sym)
27
+ end
28
+
29
+ def validate_to_sym(display_column)
30
+ return if display_column.respond_to?(:to_sym)
31
+ fail ArgumentError, DISPLAY_COLUMNS_TO_SYM_ERROR
32
+ end
33
+
34
+ def validate_display_column(display_column)
35
+ return if DCC.include?(display_column)
36
+ fail ArgumentError, format(DISPLAY_COLUMNS_ERROR, display_column)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ require 'sort/sort_consts'
3
+
4
+ module QiitaMatome
5
+ # QiitaMatome::Validators
6
+ module Validators
7
+ # SortTypeValidator
8
+ class SortTypeValidator
9
+ # rubocop:disable LineLength
10
+ SORT_TYPE_ERROR = "invalid sort_type '%s'. sort_type must be 'created_at_asc', 'created_at_desc', 'updated_at_asc', 'updated_at_desc', 'title_date_asc', 'title_date_desc', 'stock_count_asc' or 'stock_count_desc'"
11
+ # rubocop:enable LineLength
12
+
13
+ def self.validate(sort_type)
14
+ return if Sort::Consts::ALL_TYPES.include?(sort_type)
15
+ fail ArgumentError, format(SORT_TYPE_ERROR, sort_type)
16
+ end
17
+ end
18
+ end
19
+ end
File without changes
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'qiita_matome/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'qiita_matome'
8
+ spec.version = QiitaMatome::VERSION
9
+ spec.authors = ['tbpgr']
10
+ spec.email = ['tbpgr@tbpgr.jp']
11
+ spec.summary = %q(Qiita article matome generator)
12
+ spec.description = %q(Qiita article matome generator)
13
+ spec.homepage = 'https://github.com/tbpgr/qiita_matome'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'activemodel', '~> 4.0', '>= 4.0.2'
22
+ spec.add_runtime_dependency 'thor', '~> 0.18.1'
23
+
24
+ spec.add_development_dependency 'rspec', '~> 2.14', '>= 2.14.1'
25
+ spec.add_development_dependency 'simplecov', '~> 0.8', '>= 0.8.2'
26
+ spec.add_development_dependency 'bundler', '~> 1.6'
27
+ spec.add_development_dependency 'rake', '~> 0'
28
+ end
@@ -0,0 +1,25 @@
1
+ # RuboCop まとめ タイトル昇順
2
+
3
+ 更新日: 2014/07/01 22:51:13
4
+
5
+ |No.|タイトル|作成日|ストック数|
6
+ |--:|:--|:--:|--:|
7
+ |1|[RuboCop Style/AccessModifierIndentation](http://qiita.com/tbpgr/items/706d2b93052154772f18)|2014/06/15 00:53:36|4|
8
+ |2|[RuboCop Style/AlignHash EnforcedColonStyle](http://qiita.com/tbpgr/items/b23d30a3b6284e800b60)|2014/06/16 21:41:26|4|
9
+ |3|[RuboCop Style/AlignHash EnforcedHashRocketStyle](http://qiita.com/tbpgr/items/36788d9da32e7a6d6f43)|2014/06/15 23:19:06|3|
10
+ |4|[RuboCop Style/AlignHash EnforcedLastArgumentHashStyle](http://qiita.com/tbpgr/items/e07749ec716247f0a409)|2014/06/17 21:25:54|4|
11
+ |5|[RuboCop Style/AlignParameters EnforcedStyle](http://qiita.com/tbpgr/items/414e3aad8c3b56d2ce04)|2014/06/18 22:44:12|4|
12
+ |6|[RuboCop Style/BlockNesting](http://qiita.com/tbpgr/items/21cca635527eb03e64f2)|2014/06/19 21:48:37|3|
13
+ |7|[RuboCop Style/BracesAroundHashParameters EnforcedStyle](http://qiita.com/tbpgr/items/8932a19d154fc3d7c142)|2014/06/20 21:27:07|3|
14
+ |8|[RuboCop Style/CaseIndentation Indent One Step](http://qiita.com/tbpgr/items/d14e825f6eb9c9175d6a)|2014/06/22 21:18:23|2|
15
+ |9|[RuboCop Style/CaseIndentation IndentWhenRelativeTo](http://qiita.com/tbpgr/items/7323c764e3ae046a0fde)|2014/06/21 13:31:37|2|
16
+ |10|[RuboCop Style/ClassAndModuleChildren EnforcedStyle](http://qiita.com/tbpgr/items/61b9da235701df919ae5)|2014/06/23 22:12:53|2|
17
+ |11|[RuboCop Style/ClassLength](http://qiita.com/tbpgr/items/44087a9f4c6548043ace)|2014/06/24 20:28:50|2|
18
+ |12|[RuboCop Style/CollectionMethods PreferredMethods](http://qiita.com/tbpgr/items/a982166bbd473fcd4e6e)|2014/06/26 00:06:37|1|
19
+ |13|[RuboCop Style/CommentAnnotation](http://qiita.com/tbpgr/items/5b0cee75305cef801851)|2014/06/26 21:29:33|2|
20
+ |14|[RuboCop Style/CyclomaticComplexity](http://qiita.com/tbpgr/items/693f37d763c6ea5f9e9b)|2014/06/27 21:55:52|2|
21
+ |15|[RuboCop Style/DotPosition](http://qiita.com/tbpgr/items/c53f86c876f73c1aa5a8)|2014/06/28 23:08:32|2|
22
+ |16|[RuboCop Style/EmptyLineBetweenDefs](http://qiita.com/tbpgr/items/2872f2a27430372d43e4)|2014/06/29 19:49:56|2|
23
+ |17|[RuboCop Style/FileName](http://qiita.com/tbpgr/items/97fc9186e59d607b1ecf)|2014/06/30 21:56:25|1|
24
+ |18|[RuboCopの警告をコメントで無効化する方法](http://qiita.com/tbpgr/items/a9000c5c6fa92a46c206)|2014/06/08 21:27:21|6|
25
+
@@ -0,0 +1,341 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'display/display_consts'
4
+ require 'display/displayer'
5
+ require 'models/article'
6
+ require 'models/articles'
7
+
8
+ # rubocop:disable LineLength, UnusedMethodArgument
9
+ describe QiitaMatome::Display::Displayer do
10
+ context :new do
11
+ cases = [
12
+ {
13
+ case_no: 1,
14
+ case_title: 'valid args',
15
+ articles: [QiitaMatome::Article.new, QiitaMatome::Article.new],
16
+ display_columns: [:no, :title],
17
+ expected_display_columns: [:no, :title]
18
+ },
19
+ {
20
+ case_no: 2,
21
+ case_title: 'invalid articles class "String"',
22
+ articles: 'String',
23
+ display_columns: [:no, :title],
24
+ expect_error: true
25
+ },
26
+ {
27
+ case_no: 3,
28
+ case_title: 'invalid article class "String"',
29
+ articles: [QiitaMatome::Article.new, 'String'],
30
+ display_columns: [:no, :title],
31
+ expect_error: true
32
+ },
33
+ {
34
+ case_no: 4,
35
+ case_title: 'invalid display_columns "invalid"',
36
+ articles: [QiitaMatome::Article.new, QiitaMatome::Article.new],
37
+ display_columns: 'invalid',
38
+ expect_error: true
39
+ },
40
+ {
41
+ case_no: 5,
42
+ case_title: 'valid args(auto convert display_columns)',
43
+ articles: [QiitaMatome::Article.new, QiitaMatome::Article.new],
44
+ display_columns: 'title',
45
+ expected_display_columns: [:title]
46
+ },
47
+ {
48
+ case_no: 6,
49
+ case_title: 'invalid display_columns than haven\'t to_sym method.',
50
+ articles: [QiitaMatome::Article.new, QiitaMatome::Article.new],
51
+ display_columns: 1,
52
+ expect_error: true
53
+ },
54
+ {
55
+ case_no: 7,
56
+ case_title: 'valid args(updated_at)',
57
+ articles: [QiitaMatome::Article.new, QiitaMatome::Article.new],
58
+ display_columns: [:created_at, :updated_at],
59
+ expected_display_columns: [:created_at, :updated_at]
60
+ }
61
+ ]
62
+
63
+ cases.each do |c|
64
+ it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
65
+ begin
66
+ case_before c
67
+
68
+ # -- given --
69
+ if c[:expect_error]
70
+ -> { QiitaMatome::Display::Displayer.new('title', c[:articles], c[:display_columns]) }.should raise_error(ArgumentError)
71
+ next
72
+ end
73
+ qdd = QiitaMatome::Display::Displayer.new('title', c[:articles], c[:display_columns])
74
+
75
+ # -- when --
76
+ actual_articles = qdd.articles
77
+ actual_display_columns = qdd.display_columns
78
+
79
+ # -- then --
80
+ expect(actual_articles).to eq(c[:articles])
81
+ expect(actual_display_columns).to eq(c[:expected_display_columns])
82
+ ensure
83
+ case_after c
84
+ end
85
+ end
86
+
87
+ def case_before(c)
88
+ # implement each case before
89
+ end
90
+
91
+ def case_after(c)
92
+ # implement each case after
93
+ end
94
+ end
95
+ end
96
+
97
+ context :display_title do
98
+ cases = [
99
+ {
100
+ case_no: 1,
101
+ case_title: 'valid args',
102
+ articles: [QiitaMatome::Article.new, QiitaMatome::Article.new],
103
+ title: 'title1',
104
+ expected: '# title1'
105
+ }
106
+ ]
107
+
108
+ cases.each do |c|
109
+ it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
110
+ begin
111
+ case_before c
112
+
113
+ # -- given --
114
+ qdd = QiitaMatome::Display::Displayer.new(c[:title], c[:articles])
115
+
116
+ # -- when --
117
+ actual = qdd.display_title
118
+
119
+ # -- then --
120
+ expect(actual).to eq(c[:expected])
121
+ ensure
122
+ case_after c
123
+ end
124
+ end
125
+
126
+ def case_before(c)
127
+ # implement each case before
128
+ end
129
+
130
+ def case_after(c)
131
+ # implement each case after
132
+ end
133
+ end
134
+ end
135
+
136
+ context :table_header do
137
+ TABLE_HEADER_ARTICLE = QiitaMatome::Article.new(
138
+ 'user' => { 'id' => 99_999, 'url_name' => 'tbpgr', 'profile_image_url' => '' },
139
+ 'title' => 'title1',
140
+ 'created_at' => '2014-06-18 22:37:54 +0900',
141
+ 'updated_at' => '2014-06-26 02:25:11 +0900',
142
+ 'tags' => [{ 'name' => 'Ruby', 'url_name' => 'ruby', 'icon_url' => '', 'versions' => [] }],
143
+ 'stock_count' => 2
144
+ )
145
+
146
+ cases = [
147
+ {
148
+ case_no: 1,
149
+ case_title: 'valid args',
150
+ articles: [TABLE_HEADER_ARTICLE, QiitaMatome::Article.new],
151
+ display_columns: [:no, :title],
152
+ expected: <<-EOS
153
+ |No.|タイトル|
154
+ |--:|:--|
155
+ EOS
156
+ },
157
+ {
158
+ case_no: 2,
159
+ case_title: 'full display args',
160
+ articles: [TABLE_HEADER_ARTICLE, QiitaMatome::Article.new],
161
+ display_columns: [:no, :title, :created_at, :stock_count],
162
+ expected: <<-EOS
163
+ |No.|タイトル|作成日|ストック数|
164
+ |--:|:--|:--:|--:|
165
+ EOS
166
+ }
167
+ ]
168
+
169
+ cases.each do |c|
170
+ it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
171
+ begin
172
+ case_before c
173
+
174
+ # -- given --
175
+ qdd = QiitaMatome::Display::Displayer.new(c[:title], c[:articles], c[:display_columns])
176
+
177
+ # -- when --
178
+ actual = qdd.table_header
179
+
180
+ # -- then --
181
+ expect(actual).to eq(c[:expected])
182
+ ensure
183
+ case_after c
184
+ end
185
+ end
186
+
187
+ def case_before(c)
188
+ # implement each case before
189
+ end
190
+
191
+ def case_after(c)
192
+ # implement each case after
193
+ end
194
+ end
195
+ end
196
+
197
+ context :display_article do
198
+ DISPLAY_ARTICLE = QiitaMatome::Article.new(
199
+ 'uuid' => 'd1ed617093609ccedbee',
200
+ 'user' => { 'id' => 99_999, 'url_name' => 'tbpgr', 'profile_image_url' => '' },
201
+ 'title' => 'title1',
202
+ 'created_at' => '2014-06-18 22:37:54 +0900',
203
+ 'updated_at' => '2014-06-26 02:25:11 +0900',
204
+ 'tags' => [{ 'name' => 'Ruby', 'url_name' => 'ruby', 'icon_url' => '', 'versions' => [] }],
205
+ 'stock_count' => 2
206
+ )
207
+
208
+ cases = [
209
+ {
210
+ case_no: 1,
211
+ case_title: 'valid args',
212
+ articles: [DISPLAY_ARTICLE, QiitaMatome::Article.new],
213
+ article: DISPLAY_ARTICLE,
214
+ no: 1,
215
+ display_columns: [:no, :title],
216
+ expected: '|1|[title1](http://qiita.com/tbpgr/items/d1ed617093609ccedbee)|'
217
+ },
218
+ {
219
+ case_no: 2,
220
+ case_title: 'full display args',
221
+ articles: [DISPLAY_ARTICLE, QiitaMatome::Article.new],
222
+ article: DISPLAY_ARTICLE,
223
+ no: 1,
224
+ display_columns: [:no, :title, :created_at, :stock_count],
225
+ expected: '|1|[title1](http://qiita.com/tbpgr/items/d1ed617093609ccedbee)|2014/06/18 22:37:54|2|'
226
+ }
227
+ ]
228
+
229
+ cases.each do |c|
230
+ it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
231
+ begin
232
+ case_before c
233
+
234
+ # -- given --
235
+ qdd = QiitaMatome::Display::Displayer.new('title', c[:articles], c[:display_columns])
236
+
237
+ # -- when --
238
+ actual = qdd.display_article(c[:no], c[:article])
239
+
240
+ # -- then --
241
+ expect(actual).to eq(c[:expected])
242
+ ensure
243
+ case_after c
244
+ end
245
+ end
246
+
247
+ def case_before(c)
248
+ # implement each case before
249
+ end
250
+
251
+ def case_after(c)
252
+ # implement each case after
253
+ end
254
+ end
255
+ end
256
+
257
+ context :display_articles do
258
+ DISPLAY_ARTICLES = [
259
+ QiitaMatome::Article.new(
260
+ 'uuid' => 'd1ed617093609ccedbee',
261
+ 'user' => { 'id' => 99_999, 'url_name' => 'tbpgr', 'profile_image_url' => '' },
262
+ 'title' => 'title1',
263
+ 'created_at' => '2014-06-18 22:37:54 +0900',
264
+ 'updated_at' => '2014-06-26 02:25:11 +0900',
265
+ 'tags' => [{ 'name' => 'Ruby', 'url_name' => 'ruby', 'icon_url' => '', 'versions' => [] }],
266
+ 'stock_count' => 2
267
+ ),
268
+ QiitaMatome::Article.new(
269
+ 'uuid' => 'd1ed617093609ccedbef',
270
+ 'user' => { 'id' => 99_999, 'url_name' => 'tbpgr', 'profile_image_url' => '' },
271
+ 'title' => 'title2',
272
+ 'created_at' => '2014-06-18 22:37:53 +0900',
273
+ 'updated_at' => '2014-06-26 02:25:09 +0900',
274
+ 'tags' => [{ 'name' => 'Ruby', 'url_name' => 'ruby', 'icon_url' => '', 'versions' => [] }],
275
+ 'stock_count' => 3
276
+ ),
277
+ QiitaMatome::Article.new(
278
+ 'uuid' => 'd1ed617093609ccedbeg',
279
+ 'user' => { 'id' => 99_999, 'url_name' => 'tbpgr', 'profile_image_url' => '' },
280
+ 'title' => 'title3',
281
+ 'created_at' => '2014-06-18 22:37:52 +0900',
282
+ 'updated_at' => '2014-06-26 02:25:10 +0900',
283
+ 'tags' => [{ 'name' => 'Ruby', 'url_name' => 'ruby', 'icon_url' => '', 'versions' => [] }],
284
+ 'stock_count' => 10
285
+ )
286
+ ]
287
+
288
+ cases = [
289
+ {
290
+ case_no: 1,
291
+ case_title: 'valid args',
292
+ articles: DISPLAY_ARTICLES,
293
+ display_columns: [:no, :title],
294
+ expected: <<-EOS
295
+ |1|[title1](http://qiita.com/tbpgr/items/d1ed617093609ccedbee)|
296
+ |2|[title2](http://qiita.com/tbpgr/items/d1ed617093609ccedbef)|
297
+ |3|[title3](http://qiita.com/tbpgr/items/d1ed617093609ccedbeg)|
298
+ EOS
299
+ },
300
+ {
301
+ case_no: 2,
302
+ case_title: 'full display args',
303
+ articles: DISPLAY_ARTICLES,
304
+ display_columns: [:no, :title, :created_at, :updated_at, :stock_count],
305
+ expected: <<-EOS
306
+ |1|[title1](http://qiita.com/tbpgr/items/d1ed617093609ccedbee)|2014/06/18 22:37:54|2014/06/26 02:25:11|2|
307
+ |2|[title2](http://qiita.com/tbpgr/items/d1ed617093609ccedbef)|2014/06/18 22:37:53|2014/06/26 02:25:09|3|
308
+ |3|[title3](http://qiita.com/tbpgr/items/d1ed617093609ccedbeg)|2014/06/18 22:37:52|2014/06/26 02:25:10|10|
309
+ EOS
310
+ }
311
+ ]
312
+
313
+ cases.each do |c|
314
+ it "|case_no=#{c[:case_no]}|case_title=#{c[:case_title]}" do
315
+ begin
316
+ case_before c
317
+
318
+ # -- given --
319
+ qdd = QiitaMatome::Display::Displayer.new('title', c[:articles], c[:display_columns])
320
+
321
+ # -- when --
322
+ actual = qdd.display_articles
323
+
324
+ # -- then --
325
+ expect(actual).to eq(c[:expected])
326
+ ensure
327
+ case_after c
328
+ end
329
+ end
330
+
331
+ def case_before(c)
332
+ # implement each case before
333
+ end
334
+
335
+ def case_after(c)
336
+ # implement each case after
337
+ end
338
+ end
339
+ end
340
+ end
341
+ # rubocop:enable LineLength, UnusedMethodArgument