simple2ch 0.1.8 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +25 -0
  4. data/.travis.yml +8 -0
  5. data/README.md +24 -31
  6. data/UPDATES.md +46 -9
  7. data/lib/simple2ch.rb +67 -83
  8. data/lib/simple2ch/bbs.rb +54 -0
  9. data/lib/simple2ch/board.rb +26 -50
  10. data/lib/simple2ch/dat.rb +22 -20
  11. data/lib/simple2ch/regex.rb +16 -0
  12. data/lib/simple2ch/{res.rb → response.rb} +58 -57
  13. data/lib/simple2ch/simple2ch_error.rb +9 -0
  14. data/lib/simple2ch/thread.rb +113 -0
  15. data/lib/simple2ch/version.rb +1 -1
  16. data/simple2ch.gemspec +8 -0
  17. data/spec/bbs_spec.rb +30 -0
  18. data/spec/board_spec.rb +89 -54
  19. data/spec/dat_spec.rb +20 -19
  20. data/spec/response_spec.rb +131 -0
  21. data/spec/simple2ch_spec.rb +19 -50
  22. data/spec/spec_helper.rb +65 -37
  23. data/spec/thread_spec.rb +76 -0
  24. data/spec/vcr/Simple2ch_BBS/_boards/use_cache/behaves_like_boards/from_2ch_sc/1_1_1_1_1_2.yml +1117 -0
  25. data/spec/vcr/Simple2ch_BBS/_boards/use_cache/behaves_like_boards/from_open2ch_net/1_1_1_1_2_2.yml +1136 -0
  26. data/spec/vcr/Simple2ch_BBS/_boards/use_force_reload/behaves_like_boards/from_2ch_sc/1_1_2_1_1_2.yml +1117 -0
  27. data/spec/vcr/Simple2ch_BBS/_boards/use_force_reload/behaves_like_boards/from_2ch_sc/1_1_2_1_1_3.yml +1117 -0
  28. data/spec/vcr/Simple2ch_BBS/_boards/use_force_reload/behaves_like_boards/from_open2ch_net/1_1_2_1_2_2.yml +1136 -0
  29. data/spec/vcr/Simple2ch_BBS/_boards/use_force_reload/behaves_like_boards/from_open2ch_net/1_1_2_1_2_3.yml +1136 -0
  30. data/spec/vcr/Simple2ch_Board/_threads/1_4_1.yml +1238 -0
  31. data/spec/vcr/Simple2ch_Board/_threads/1_4_2.yml +1238 -0
  32. data/spec/vcr/Simple2ch_Board/_threads/1_4_3.yml +1238 -0
  33. data/spec/vcr/Simple2ch_Board/_threads/1_4_7.yml +1238 -0
  34. data/spec/vcr/Simple2ch_Board/_threads/1_4_8.yml +1238 -0
  35. data/spec/vcr/Simple2ch_Board/_threads/1_4_9.yml +1238 -0
  36. data/spec/vcr/Simple2ch_Dat/should_have_responses/1_2_1.yml +953 -0
  37. data/spec/vcr/Simple2ch_Dat/should_have_responses/1_2_3.yml +953 -0
  38. data/spec/vcr/Simple2ch_Dat/should_have_responses/1_2_4.yml +953 -0
  39. data/spec/vcr/Simple2ch_Dat/should_have_responses/size/1_2_2_1.yml +953 -0
  40. data/spec/vcr/Simple2ch_Response/_anchors/when_a_thre_have_both_id_and_non-id_responses/1_2_7_1.yml +5321 -0
  41. data/spec/vcr/Simple2ch_Response/_parse/when_real_data/when_2ch_sc/1_1_2_1_1.yml +1599 -0
  42. data/spec/vcr/Simple2ch_Response/_parse/when_real_data/when_open2ch_net/1_1_2_2_1.yml +1465 -0
  43. data/spec/vcr/Simple2ch_Thread/_new/2ch_sc/1_1_1_1.yml +1410 -0
  44. data/spec/vcr/Simple2ch_Thread/_new/2ch_sc/1_1_1_2.yml +1692 -0
  45. data/spec/vcr/Simple2ch_Thread/_new/open2ch_net/1_1_2_1.yml +1410 -0
  46. data/spec/vcr/Simple2ch_Thread/_new/open2ch_net/1_1_2_2.yml +1999 -0
  47. data/spec/vcr/Simple2ch_Thread/_responses/1_2_1.yml +1599 -0
  48. data/spec/vcr/Simple2ch_Thread/_responses/first/1_2_2_1.yml +1599 -0
  49. data/spec/vcr/Simple2ch_Thread/_responses/first/1_2_3_1.yml +1599 -0
  50. data/spec/vcr/Simple2ch_Thread/_title/1_3_1.yml +1599 -0
  51. data/spec/vcr/Simple2ch_Thread/_title/size/1_3_2_1.yml +1599 -0
  52. metadata +185 -11
  53. data/lib/simple2ch/simple2ch_exception.rb +0 -7
  54. data/lib/simple2ch/thre.rb +0 -140
  55. data/spec/res_spec.rb +0 -123
  56. data/spec/thre_spec.rb +0 -122
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a828cfa87f21889ba2484cb3d9671f105ef269ae
4
- data.tar.gz: 2d966a2833cd5e664f0de975605f7f39c41c9d22
3
+ metadata.gz: 43d1380870c6d075419424891d4352ef6186d990
4
+ data.tar.gz: 4aee2a9072f121ffdb6cb8e2cbcf3fa4fb4abb37
5
5
  SHA512:
6
- metadata.gz: 2978f20a31058b412ea155168b9b5df645079f8938398a38f041ff17520e04958f13b7938cfb0e3d94bd4f90ad6b9416ceede5e58116222f81312b74775556a4
7
- data.tar.gz: e8b2bc6562634309cf9a87e5b2f487b82b5c8a4aefb3563588a01fca7fdd7d2dcc755e6e419106f13795a34987b56ba4c671fd23186ec6bacd927f9ff40650f9
6
+ metadata.gz: 90fe3acbd460eca6f3c405fffec2e4392a18c4adf65e8660289905c63cc61eebfc366cc8b9a18b2fd64e036b4628dbd5131b191893796dcb125b7638be01a018
7
+ data.tar.gz: 2f2dd214ed6f8579e257e07b98165ae4746e88c715a849c27d3c2712a8b19c375f959803cc92720b489483015ffea9241d80264f5238decd6f3b18581051ca75
data/.gitignore CHANGED
@@ -119,3 +119,4 @@ build/
119
119
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
120
120
  .rvmrc
121
121
 
122
+ .bin
data/.rubocop.yml ADDED
@@ -0,0 +1,25 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+ Includes:
4
+ - Gemfile
5
+ - Rakefile
6
+ Excludes:
7
+ - bin/**
8
+ - vendor/**
9
+ - .bundle/**
10
+
11
+ SymbolArray:
12
+ Enabled: true
13
+
14
+ CollectionMethods:
15
+ PreferredMethods:
16
+ collect: 'map'
17
+ inject: 'reduce'
18
+ detect: 'find'
19
+ find_all: 'select'
20
+
21
+ SpaceInsideHashLiteralBraces:
22
+ EnforcedStyleIsWithSpaces: false
23
+
24
+ Style/AsciiComments:
25
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.7
4
+ - 2.2.2
5
+ - 2.2.3
6
+ - 2.3.0
7
+ bundler_args: --jobs=2
8
+ script: bundle exec rspec
data/README.md CHANGED
@@ -4,18 +4,19 @@
4
4
  Ruby用の2chの簡易リーダーです。
5
5
 
6
6
  ![gem version](https://badge.fury.io/rb/simple2ch.svg)
7
- [リファレンス](http://dogwood008.github.io/simple2ch/)
7
+ [リファレンス](http://www.rubydoc.info/gems/simple2ch/)
8
8
 
9
9
  ## 更新内容
10
10
 
11
- * [v0.1.8]
12
- * 機能追加
13
- * URLからスレを取得した時に,subject.txtに当該スレが無い場合,タイトルをdatの解析結果から取得するよう変更
14
- * [v0.1.7]
15
- * 機能追加
16
- * Thre#url, Thre#dat_urlの追加
17
- * バグ修正
18
- * エンコーディング関連
11
+ ## [v1.1.0]
12
+
13
+ * 全面的にメソッド数を見直し、大幅なリファクタリング
14
+ * v0.X 系とは互換性一部なし
15
+ * クラス名変更: Res -> Response, Thre -> Thread
16
+
17
+ ## [v0.1.9]
18
+
19
+ * 著者をプレインテキストで返すメソッドを追加
19
20
 
20
21
  ## Installation
21
22
 
@@ -38,48 +39,41 @@ Or install it yourself as:
38
39
  require 'simple2ch'
39
40
  ```
40
41
 
41
- ### Simple2ch
42
+ ### Simple2ch:BBS
42
43
 
43
44
  ```ruby
44
- boards = Simple2ch.boards 'http://open2ch.net' #=> [#<Simple2ch::Board>, ..., #<Simple2ch::Board>]
45
+ bbs = Simple2ch::BBS(:sc)
46
+ bbs.boards #=> [#<Simple2ch::Board>, ...]
45
47
  ```
46
48
 
47
49
  ### Simple2ch::Board
50
+
48
51
  ```ruby
49
- board = boards.find{|b| b.title == 'プログラム'} #=> #<Simple2ch::Board>
50
- board.title #=> "プログラム"
51
- board.thres #=> [#<Simple2ch::Thre>, ..., #<Simple2ch::Thre>]
52
+ news_boards = bbs.boards.find_all { |b| b.title.include?('ニュース') } #=> [#<Simple2ch::Board>...]
53
+ news_board = news_boards.first
54
+ news_board.title #=> "ニュース速報α"
55
+ news_board.threads #=> [#<Simple2ch::Thread>, ...]
52
56
  ```
53
57
 
54
58
  ### Simple2ch::Thre
55
59
 
56
60
  ```ruby
57
- thre = board.thres.find{|t| t.title == 'さぁRubyはじめるよ'} #=> #<Simple2ch::Thre>
58
- reses = thre.reses #=> [#<Simple2ch::Res>, ..., #<Simple2ch::Res>]
61
+ thread = news_board.threads.first
62
+ thread.resonses #=> [#<Simple2ch::Response>, ...]
59
63
  ```
60
64
 
61
65
  #### URLを直接指定して取得
62
66
 
63
67
  ```ruby
64
- thre = Simple2ch::Thre.create_from_url('http://toro.open2ch.net/test/read.cgi/tech/1371956681/l50') #=> #<Simple2ch::Thre>
65
- thre.title #=> "さぁRubyはじめるよ"
66
- reses = thre.reses
67
- ```
68
-
69
- #### 板を指定して取得
70
-
71
- ```ruby
72
- board = Simple2ch::Board.new('ニュー速VIP', 'http://viper.open2ch.net/news4vip/')
73
- thres = board.thres #=>[#<Simple2ch::Thre>, ..., #<Simple2ch::Thre>]
74
- thre = thres.find{|t| t.title == 'プログラム'}
75
- reses = thre.reses
68
+ thread = Simple2ch::Thread.new('http://toro.open2ch.net/test/read.cgi/tech/1371956681/') #=> #<Simple2ch::Thre>
69
+ thread.title #=> "さぁRubyはじめるよ"
76
70
  ```
77
71
 
78
-
79
72
  ### Simple2ch::Res
80
73
 
81
74
  ```ruby
82
- res = reses[0] #=> #<Simple2ch::Res>
75
+ thread.responses #=> [#<Simple2ch::Response>, ...]
76
+ res = thread.responses[0] #=> #<Simple2ch::Response>
83
77
  res.res_num #=> 1
84
78
  res.contents #=> "Ruby覚えたいなぁ"
85
79
  res.author #=> "s"
@@ -88,7 +82,6 @@ res.date #=> 2013-06-23 12:04:41 +0900
88
82
  res.mail #=> ""
89
83
  ```
90
84
 
91
-
92
85
  ## Contributing
93
86
 
94
87
  1. Fork it ( https://github.com/dogwood008/simple2ch/fork )
data/UPDATES.md CHANGED
@@ -1,20 +1,53 @@
1
- [v0.1.5]
1
+ ## [v1.1.0]
2
+
3
+ * 全面的にメソッド数を見直し、大幅なリファクタリング
4
+ * v0.X 系とは互換性一部なし
5
+ * クラス名変更: Res -> Response, Thre -> Thread
6
+
7
+ ## [v0.1.9]
8
+
9
+ * 著者をプレインテキストで返すメソッドを追加
10
+
11
+ ## [v0.1.8]
12
+
13
+ * 機能追加
14
+ * URLからスレを取得した時に,subject.txtに当該スレが無い場合,タイトルをdatの解析結果から取得するよう変更
15
+
16
+ ## [v0.1.7]
17
+
18
+ * 機能追加
19
+ * Thre#url, Thre#dat_urlの追加
20
+ * バグ修正
21
+ * エンコーディング関連
22
+
23
+ ## [v0.1.6]
24
+
25
+ * 機能追加
26
+ * 板一覧の取得に対応
27
+ * URLからスレの取得に対応
28
+
29
+
30
+ ## [v0.1.5]
31
+
2
32
  * デバッグ
3
33
  * StandardErrorで例外を捕縛できない問題を修正
4
34
  * 機能追加
5
35
  * おーぷん2ちゃんねる対応
6
-
7
- [v0.1.4]
36
+
37
+ ## [v0.1.4]
38
+
8
39
  * デバッグ
9
40
  * Thre#resesを実行した際に、IDを持たないレスがあれば、DatParseExceptionが起きる問題を修正
10
41
  * エイリアス追加
11
42
  * Thre#resをThre#resesのエイリアスに設定
12
43
 
13
- [v0.1.3]
44
+ ## [v0.1.3]
45
+
14
46
  * デバッグ
15
47
  * Res#received_anchors呼び出し時にNoThreGivenExceptionが起きる場合がある問題を修正
16
48
 
17
- [v0.1.2]
49
+ ## [v0.1.2]
50
+
18
51
  * リファクタリングとデバッグ
19
52
  * メソッド修正
20
53
  * Thre#reses(Array<Fixnum>)で指定したレス番号のレスを取得
@@ -25,14 +58,16 @@
25
58
  * Res#received_anchors(Thre)
26
59
  * 自レスへの被レスを返す
27
60
 
28
- [v0.1.1]
61
+ ## [v0.1.1]
62
+
29
63
  * メソッド追加
30
64
  * Res#anchorsの追加
31
65
  * レス中のアンカーを抽出する
32
66
  * 必要gemの追加
33
67
  * Charwidthを追加
34
68
 
35
- [v0.1.0]
69
+ ## [v0.1.0]
70
+
36
71
  * メソッド名の変更
37
72
  * Thre.new から Thre.parse に変更
38
73
  * Thre.newは引数の数を変更
@@ -42,7 +77,8 @@
42
77
  * その他
43
78
  * その他微細な修正
44
79
 
45
- [v0.0.2]
80
+ ## [v0.0.2]
81
+
46
82
  * メソッド名の変更
47
83
  * Board#threads から Board#thres に変更
48
84
  * ドキュメントの再生成
@@ -51,5 +87,6 @@
51
87
  * 使用法などを追加
52
88
  * yardの結果を追加
53
89
 
54
- [v0.0.1]
90
+ ## [v0.0.1]
91
+
55
92
  * 初版
data/lib/simple2ch.rb CHANGED
@@ -1,108 +1,92 @@
1
- require "simple2ch/version"
1
+ require 'simple2ch/version'
2
+ require 'singleton'
2
3
 
3
4
  module Simple2ch
4
- DEBUG = false
5
-
6
- require 'simple2ch/simple2ch_exception'
7
- require 'simple2ch/board'
8
- require 'simple2ch/dat'
9
- require 'simple2ch/res'
10
- require 'simple2ch/thre'
5
+ require_relative './simple2ch/simple2ch_error'
6
+ require_relative './simple2ch/board'
7
+ require_relative './simple2ch/dat'
8
+ require_relative './simple2ch/response'
9
+ require_relative './simple2ch/thread'
10
+ require_relative './simple2ch/regex'
11
+ require_relative './simple2ch/bbs'
12
+ require 'socket'
11
13
  require 'open-uri'
12
14
  require 'time'
13
15
  require 'charwidth'
14
- require 'pp' if DEBUG
15
-
16
- def self.root
17
- File.dirname __dir__
18
- end
19
-
20
- # Module variables
21
- @@boards = {}
16
+ require 'retryable'
17
+ require 'bbs_2ch_url_validator'
18
+ require 'pry'
22
19
 
23
20
  # HTTPでGETする
24
- # @param [URI] url URL
21
+ # @param [URI or Bbs2chUrlValidator::UrlInfo or String] url URL
25
22
  # @return [String] 取得本文
26
- def self.fetch(url)
27
- encode = if url.to_s.index('subject.txt') || url.to_s.index('.dat') || url.to_s.index('bbsmenu')
28
- 'SHIFT_JIS'
29
- else
30
- 'UTF-8'
31
- end
32
- OpenURI.open_uri(url, 'r:binary').read.force_encoding(encode).encode('utf-8', undef: :replace, invalid: :replace, replace: '〓')
33
- end
34
-
35
- # bbsmenuのURLが渡されればセットして,板リストを返す
36
- # @param [String] bbsmenu_url bbs_menuのURL
37
- # @option [Boolean] force_refresh キャッシュを利用せず板リストを再取得する
38
- # @return [Array<Simple2ch::Board>] 板リスト
39
- def self.boards(bbsmenu_url=nil, force_refresh:nil)
40
- if bbsmenu_url
41
- bbsmenu_urls = {
42
- net: 'http://menu.2ch.net/bbsmenu.html', sc: 'http://2ch.sc/bbsmenu.html', open: 'http://open2ch.net/bbsmenu.html'
43
- }
44
- # http://www.rubular.com/r/u1TJbQAULD
45
- board_extract_regex = /<A HREF=http:\/\/(?<subdomain>\w+).(?<openflag>open|)2ch.(?<tld>sc|net)\/(?<board_name>\w+)\/>(?<board_name_ja>.+)<\/A>/
46
- type_of_2ch = self.type_of_2ch(bbsmenu_url)
47
-
48
- if force_refresh || (boards=@@boards.fetch(type_of_2ch, [])).size == 0
49
- prepared_bbsmenu_url = bbsmenu_urls[type_of_2ch]
50
-
51
- data = nil
52
- boards_array = []
53
-
54
- raise RuntimeError, "Failed to fetch #{url}" if (data = fetch(URI.parse(prepared_bbsmenu_url))).empty?
55
- raise RuntimeError, "Failed to parse #{url}" if (boards_array=data.scan(board_extract_regex).uniq).empty?
56
-
57
- boards_array.each do |b|
58
- boards << Simple2ch::Board.new(b[4],"http://#{b[0]}.#{b[1]}2ch.#{b[2]}/#{b[3]}/")
59
- end
60
- @@boards[type_of_2ch] = boards
61
- end
23
+ def self.fetch(url, encode = nil)
24
+ url_obj = URI.parse(url.to_s)
25
+ encode ||= encoded_in_sjis?(url) ? 'sjis' : 'utf-8'
26
+ errors_to_retry = [OpenURI::HTTPError, SocketError]
27
+ Retryable.retryable(tries: 5, on: errors_to_retry, sleep: 3) do
28
+ OpenURI.open_uri(url_obj, "r:#{encode}")
29
+ .read
30
+ .encode('utf-8', undef: :replace, invalid: :replace, replace: '〓')
62
31
  end
63
- @@boards[type_of_2ch]
64
32
  end
65
33
 
66
34
  # 2chのタイプを返す
67
35
  # @param [String] url URL
68
36
  # @return [Symbol] :open or :net or :sc
69
- # @raise [NotA2chUrlException] 2chのURLでないURLが与えられた際に発生
37
+ # @raise [NotA2chUrlError] 2chのURLでないURLが与えられた際に発生
70
38
  def self.type_of_2ch(url)
71
- parsed_url = self.parse_url(url)
72
- openflag = parsed_url[:openflag]
73
- tld = parsed_url[:tld]
74
- if openflag && tld=='net'
39
+ parsed_url = Bbs2chUrlValidator::URL.parse(url)
40
+ raise NotA2chUrlError, "Given URL: #{url}" unless parsed_url
41
+ case true
42
+ when parsed_url.is_open && parsed_url.tld == 'net'
75
43
  :open
76
- elsif !openflag && tld=='net'
44
+ when !parsed_url.is_open && parsed_url.tld == 'net'
77
45
  :net
78
- elsif !openflag && tld=='sc'
46
+ when !parsed_url.is_open && parsed_url.tld == 'sc'
79
47
  :sc
80
48
  else
81
- raise NotA2chUrlException, "Given URL: #{url}"
49
+ binding.pry
50
+ raise NotA2chUrlError, "Given URL: #{url}"
82
51
  end
83
52
  end
84
53
 
85
- # URLを分解する
86
- # @param [String] url URL
87
- # @return [Array<String>] 結果(thread_key等が該当無しの場合,nilを返す)
88
- # @raise [NotA2chUrlException] 2chのURLでないURLが与えられた際に発生
89
- def self.parse_url(url)
90
- # http://www.rubular.com/r/h63xdfmQIH
91
- case url.to_s
92
- when /http:\/\/(?<server_name>.+)\.(?<openflag>open)?2ch.(?<tld>net|sc)\/test\/read.cgi\/(?<board_name>.+)\/(?<thread_key>[0-9]+)/,
93
- /http:\/\/(?<server_name>.+)\.(?<openflag>open)?2ch.(?<tld>net|sc)\/(?<board_name>.+)\/subject\.txt/,
94
- /http:\/\/(?<server_name>.+)\.(?<openflag>open)?2ch\.(?<tld>net|sc)\/(?<board_name>.+)\//,
95
- /http:\/\/(?<server_name>.+)\.(?<openflag>open)?2ch\.(?<tld>net|sc)\/(?<board_name>\w+)/,
96
- /http:\/\/(?<server_name>.+)\.(?<openflag>open)?2ch.(?<tld>net|sc)\/(.+)\/dat\/(?<thread_key>[0-9]+)\.dat/,
97
- /http:\/\/(?:(?<server_name>.*)\.)?(?:(?<openflag>open)?)2ch\.(?<tld>sc|net)/
98
- {server_name: ($~[:server_name] rescue nil),
99
- board_name: ($~[:board_name] rescue nil),
100
- openflag: ($~[:openflag] rescue nil),
101
- tld: $~[:tld],
102
- thread_key: ($~[:thread_key] rescue nil) }
103
- else
104
- raise NotA2chUrlException, "Given URL: #{url}"
54
+ # @param [Object] url
55
+ # @param [Hash] type
56
+ def self.generate_url(type, url, params = {})
57
+ # bbs: http://www.2ch.sc/, http://open2ch.net/
58
+ # board: http://viper.2ch.sc/news4vip/, http://viper.open2ch.net/news4vip/
59
+ # dat: http://viper.2ch.sc/news4vip/dat/9990000001.dat, http://viper.open2ch.net/news4vip/dat/1439127670.dat
60
+ # subject: http://viper.2ch.sc/news4vip/subject.txt, http://viper.open2ch.net/news4vip/subject.txt
61
+ # setting: http://viper.2ch.sc/news4vip/SETTING.TXT, http://viper.open2ch.net/news4vip/SETTING.TXT
62
+ # thread: http://viper.2ch.sc/test/read.cgi/news4vip/9990000001/, http://viper.open2ch.net/test/read.cgi/news4vip/1439127670
63
+
64
+ url_obj = Bbs2chUrlValidator::URL.parse(url.to_s)
65
+ domain = "#{url_obj.open? ? 'open' : ''}2ch.#{url_obj.tld}"
66
+ board_name = params[:board_name] ? params[:board_name] : url_obj.board_name
67
+ case type
68
+ when :bbs
69
+ "http://www.#{domain}.#{url_obj.tld}/"
70
+ when :board
71
+ "http://#{url_obj.server_name}.#{domain}/#{board_name}/"
72
+ when :dat
73
+ url_obj.dat
74
+ when :subject
75
+ url_obj.subject
76
+ when :setting
77
+ url_obj.setting
78
+ when :thread
79
+ thread_key = params[:thread_key] ? params[:thread_key] : url_obj.thread_key
80
+ "http://#{url_obj.server_name}.#{domain}/test/read.cgi/#{board_name}/#{thread_key}/"
105
81
  end
106
82
  end
107
- end
108
83
 
84
+ private
85
+
86
+ def self.encoded_in_sjis?(url)
87
+ url.to_s.include?('subject.txt') ||
88
+ url.to_s.include?('SETTING.TXT') ||
89
+ url.to_s.include?('.dat') ||
90
+ url.to_s.include?('bbsmenu')
91
+ end
92
+ end
@@ -0,0 +1,54 @@
1
+ module Simple2ch
2
+ require 'socket'
3
+ require 'open-uri'
4
+ require 'time'
5
+ require 'charwidth'
6
+ require 'retryable'
7
+
8
+ class BBS
9
+ attr_reader :type_of_2ch, :boards, :updated_at
10
+
11
+ def initialize(type_of_2ch)
12
+ case type_of_2ch
13
+ when :sc, :open
14
+ @type_of_2ch = type_of_2ch
15
+ else
16
+ raise %{Invalid "type_of_2ch" given: #{type_of_2ch} (:sc or :open is correct.)}
17
+ end
18
+ @updated_at = Time.now
19
+ end
20
+
21
+ def root
22
+ File.dirname __dir__
23
+ end
24
+
25
+ # @option [Boolean] force_reload キャッシュを利用せず板リストを再取得する
26
+ # @return [Array<Simple2ch::Board>] 板リスト
27
+ def boards(force_reload: nil, bbsmenu_url: nil)
28
+ if force_reload
29
+ @boards = fetch_boards(bbsmenu_url)
30
+ else
31
+ @boards ||= fetch_boards(bbsmenu_url)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def fetch_boards(bbsmenu_url = nil)
38
+ bbsmenu_urls = {
39
+ sc: 'http://2ch.sc/bbsmenu.html', open: 'http://open2ch.net/bbsmenu.html'
40
+ }
41
+
42
+ bbsmenu_url = bbsmenu_urls[type_of_2ch] if bbsmenu_url.nil?
43
+ data = Simple2ch.fetch(URI.parse(bbsmenu_url))
44
+ raise "Failed to fetch #{bbsmenu_url}" if data.empty?
45
+ scaned_data = data.scan(Regex::BOARD_EXTRACT_REGEX).uniq
46
+ raise "Failed to parse #{bbsmenu_url}" if scaned_data.empty?
47
+
48
+ boards = scaned_data.map do |b|
49
+ Simple2ch::Board.new("http://#{b[0]}.#{b[1]}2ch.#{b[2]}/#{b[3]}/", title: b[4])
50
+ end
51
+ boards.compact
52
+ end
53
+ end
54
+ end