megalith 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .DS_Store
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ test/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in megalith.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Oame
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,36 @@
1
+ # Megalith
2
+
3
+ [![Build Status](https://secure.travis-ci.org/oame/megalith-ruby.png)](http://travis-ci.org/oame/megalith-ruby)
4
+
5
+ Megalith パーサー for Ruby<br>
6
+
7
+ ## Requirements
8
+
9
+ * Ruby 1.9.x
10
+
11
+ ## Installation
12
+
13
+ gem install megalith
14
+
15
+ ## Usage
16
+
17
+ require "megalith"
18
+
19
+ # 東方創想話(Megalith) をエンドポイントにする
20
+ megalith = Megalith.new("http://coolier.sytes.net:8080/sosowa/ssw_l/")
21
+
22
+ # 最新版から最初のSSを持ってくる
23
+ latest_log = megalith.get
24
+ first_novel = latest_log.first.fetch
25
+
26
+ # 作品集番号156の1320873807を持ってくる
27
+ novel = megalith.get(:log => 156, :key => 1320873807)
28
+ puts novel.text
29
+
30
+ ## Contributing
31
+
32
+ 1. Fork it
33
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
34
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
35
+ 4. Push to the branch (`git push origin my-new-feature`)
36
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new('spec')
6
+
7
+ # If you want to make this the default task
8
+ task :default => :spec
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ require "kconv"
4
+ require "net/http"
5
+ require "time"
6
+ require "uri"
7
+
8
+ $LOAD_PATH.unshift(File.expand_path("../", __FILE__))
9
+ require "megalith/version"
10
+ require "megalith/essentials"
11
+ require "megalith/scheme"
12
+
13
+ class Megalith
14
+ attr_accessor :base_url
15
+ USER_AGENT = "Megalith Ruby Wrapper #{Megalith::VERSION}"
16
+
17
+ def initialize(base_url)
18
+ @base_url = base_url
19
+ end
20
+
21
+ def get(args={})
22
+ args[:log] ||= 0
23
+ if args.has_key?(:key)
24
+ Novel.new(@base_url, args[:log], args[:key])
25
+ else
26
+ Subject.new(@base_url, args[:log])
27
+ end
28
+ end
29
+
30
+ #def search(query, args={})
31
+ # page = send_req({:mode => :search, :type => (args[:type] ? args[:type] : :insubject), :query => query.tosjis})
32
+ # parse_index(page)
33
+ #end
34
+ end
@@ -0,0 +1,55 @@
1
+ class Megalith
2
+ module Essentials
3
+ def param_serialize(parameter, add_prefix=true)
4
+ return "" unless parameter.class == Hash
5
+ ant = Hash.new
6
+ parameter.each do |key, value|
7
+ ant[key.to_sym] = value.to_s
8
+ end
9
+ param = ant.inject(""){|k,v|k+"&#{v[0]}=#{URI.escape(v[1])}"}
10
+ if add_prefix
11
+ param.sub!(/^&/,"?")
12
+ else
13
+ param.sub!(/^&/,"")
14
+ end
15
+ return param ? param : ""
16
+ end
17
+
18
+ def send_req(url)
19
+ uri = URI.parse(url)
20
+
21
+ Net::HTTP.version_1_2
22
+ Net::HTTP.start(uri.host, uri.port) do |http|
23
+ response = http.get(uri.path, 'User-Agent' => USER_AGENT)
24
+ return response.body.toutf8
25
+ end
26
+ return false
27
+ end
28
+
29
+ def fetch_subjects(base_url)
30
+ page = send_req(File.join(base_url, "sub", "subjects.txt"))
31
+ subjects = page.split("\n").map{|s| s.gsub(/[^0-9]/, "").to_i}
32
+ return subjects
33
+ end
34
+
35
+ def fetch_comments(base_url, key)
36
+ comments_page = send_req(File.join(base_url, "com", "#{key}.res.dat"))
37
+ arr = comments_page.split("\n").map{|c| c.split("<>")}
38
+ return nil if arr[0][0].include?("DOCTYPE")
39
+ comments = []
40
+ arr.each do |comment|
41
+ comments << Comment.new(
42
+ :text => comment[0],
43
+ :name => comment[1],
44
+ :email => comment[2],
45
+ :created_at => Time.parse(comment[3]),
46
+ :point => comment[4],
47
+ :hash => comment[5],
48
+ :host => comment[6],
49
+ :admin_flag => comment[7]
50
+ )
51
+ end
52
+ return comments
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,246 @@
1
+ # coding: utf-8
2
+
3
+ class Megalith
4
+ class Novel
5
+ include Essentials
6
+ attr_reader :log
7
+ attr_reader :key
8
+
9
+ def initialize(base_url, log, key)
10
+ @novel = fetch_novel(base_url, log, key)
11
+ @base_url = base_url
12
+ @log = (log < 1) ? fetch_subjects(base_url).first : log
13
+ @key = key
14
+ end
15
+
16
+ def fetch_novel(base_url, log, key)
17
+ novel_page = send_req(File.join(base_url, "dat", "#{key}.dat"))
18
+ aft = send_req(File.join(base_url, "aft", "#{key}.aft.dat"))
19
+ lines = novel_page.split("\n")
20
+ meta = lines[0].split("<>")
21
+ hash = lines[1]
22
+ text = lines[2, lines.size].join
23
+ comment_count, review_count = meta[4].split("/")
24
+ comments = fetch_comments(base_url, key)
25
+ novel = {
26
+ :title => meta[0],
27
+ :text => text,
28
+ :aft => aft,
29
+ :author => Author.new(:name => meta[1], :email => meta[2], :website => meta[3]),
30
+ :tags => meta[12].split(/[\s ]/),
31
+ :log => log,
32
+ :key => key,
33
+ :created_at => Time.at(key),
34
+ :updated_at => Time.parse(meta[7]),
35
+ :review_count => review_count,
36
+ :comment_count => comment_count,
37
+ :point => meta[5],
38
+ :rate => meta[6],
39
+ :host => meta[8],
40
+ :background_color => meta[9],
41
+ :text_color => meta[10],
42
+ :convert_newline => meta[11],
43
+ :size => text.bytesize / 1024,
44
+ :url => URI.join(base_url, "?mode=read&key=#{key}&log=#{log}").to_s,
45
+ :comments => comments
46
+ }
47
+ return novel
48
+ end
49
+
50
+ def simple_rating(point)
51
+ # Get cookie
52
+ get_params = param_serialize({
53
+ :mode => :read,
54
+ :key => @key,
55
+ :log => @log
56
+ })
57
+ uri = URI.parse(@base_url)
58
+ http = Net::HTTP.new(uri.host, uri.port)
59
+ req = Net::HTTP::Get.new(uri.path)
60
+ req["User-Agent"] = USER_AGENT
61
+ res = http.request(req, get_params)
62
+ cookie = res["Set-Cookie"]
63
+
64
+ # Post Comment
65
+ post_uri_params = param_serialize({
66
+ :mode => :update,
67
+ :key => @key,
68
+ :log => @log,
69
+ :target => :res
70
+ })
71
+ post_params = param_serialize({:body => "#EMPTY#", :point => point}, false)
72
+ req = Net::HTTP::Post.new(File.join(uri.path, post_uri_params))
73
+ req["Cookie"] = cookie
74
+ req["User-Agent"] = USER_AGENT
75
+ res = http.request(req, post_params)
76
+ return res
77
+ end
78
+
79
+ def comment(text, params={})
80
+ # Get cookie
81
+ get_params = param_serialize({
82
+ :mode => :read,
83
+ :key => @key,
84
+ :log => @log
85
+ })
86
+ uri = URI.parse(@base_url)
87
+ http = Net::HTTP.new(uri.host, uri.port)
88
+ req = Net::HTTP::Get.new(uri.path)
89
+ req["User-Agent"] = USER_AGENT
90
+ res = http.request(req, get_params)
91
+ cookie = res["Set-Cookie"]
92
+
93
+ # Post Comment
94
+ post_uri_params = param_serialize({
95
+ :mode => :update,
96
+ :key => @key,
97
+ :log => @log,
98
+ :target => :res
99
+ })
100
+ params.each do |k, v|
101
+ params[k] = v.to_s.tosjis
102
+ end
103
+ post_params = param_serialize({:body => text.tosjis}.update(params), false)
104
+ req = Net::HTTP::Post.new(File.join(uri.path, post_uri_params))
105
+ req["Cookie"] = cookie
106
+ req["User-Agent"] = USER_AGENT
107
+ res = http.request(req, post_params)
108
+ return res
109
+ end
110
+
111
+ def plain
112
+ return self.text.gsub(/(<br>|\r?\n)/, "")
113
+ end
114
+
115
+ def method_missing(action, *args)
116
+ return @novel[action.to_s.to_sym] rescue nil
117
+ end
118
+
119
+ def params() @novel.keys.map{|k|k.to_sym} ; end
120
+ alias_method :available_methods, :params
121
+
122
+ def to_hash
123
+ @novel
124
+ end
125
+ end
126
+
127
+ class Comment
128
+ attr_reader :comment
129
+
130
+ def initialize(comment)
131
+ @comment = comment
132
+ end
133
+
134
+ def method_missing(action, *args)
135
+ return @comment[action.to_s.to_sym] rescue nil
136
+ end
137
+
138
+ def params() @comment.keys.map{|k|k.to_sym} ; end
139
+ alias_method :available_methods, :params
140
+
141
+ def to_hash
142
+ @comment
143
+ end
144
+ end
145
+
146
+ class Author
147
+ attr_reader :author
148
+
149
+ def initialize(author)
150
+ @author = author
151
+ end
152
+
153
+ def method_missing(action, *args)
154
+ return @author[action.to_s.to_sym] rescue nil
155
+ end
156
+
157
+ def params() @author.keys.map{|k|k.to_sym} ; end
158
+ alias_method :available_methods, :params
159
+
160
+ def to_hash
161
+ @author
162
+ end
163
+ end
164
+
165
+ class Index
166
+ attr_reader :index
167
+ def initialize(base_url, index)
168
+ @base_url = base_url
169
+ @index = index
170
+ end
171
+
172
+ def method_missing(action, *args)
173
+ return @index[action.to_s.to_sym] rescue nil
174
+ end
175
+
176
+ def params() @index.keys.map{|k|k.to_sym} ; end
177
+ alias_method :available_methods, :params
178
+
179
+ def to_hash
180
+ @index
181
+ end
182
+
183
+ def fetch
184
+ Novel.new(@base_url, self.log, self.key)
185
+ end
186
+ alias_method :get, :fetch
187
+ end
188
+
189
+ class Subject < Array
190
+ include Essentials
191
+ attr_reader :subject
192
+
193
+ def initialize(base_url, log)
194
+ @subject = fetch_subject(base_url, log)
195
+ super(subject)
196
+ @base_url = base_url
197
+ @log = subject.first.log
198
+ end
199
+
200
+ def fetch_subject(base_url, log)
201
+ log = fetch_subjects(base_url).first if log < 1
202
+ page = send_req(File.join(base_url, "sub", "subject#{(log < 1) ? "" : log}.txt"))
203
+ subject = page.split("\n").map{|i| i.split("<>")}
204
+
205
+ indexes = []
206
+ subject.each do |index|
207
+ key = index[0].gsub(/[^0-9]/, "").to_i
208
+ comment_count, review_count = index[5].split("/")
209
+ indexes << Index.new(base_url, {
210
+ :log => log,
211
+ :key => key,
212
+ :title => index[1],
213
+ :author => index[2],
214
+ :created_at => Time.at(key),
215
+ :updated_at => Time.parse(index[8]),
216
+ :review_count => review_count,
217
+ :comment_count => comment_count,
218
+ :point => index[6],
219
+ :tags => index[13].split(/[\s ]/),
220
+ :rate => index[7].to_f,
221
+ :host => index[9],
222
+ :background_color => index[10],
223
+ :text_color => index[11],
224
+ :convert_newline => index[12],
225
+ :size => index[14].to_f,
226
+ :url => URI.join(base_url, "?mode=read&key=#{key}&log=#{log}").to_s
227
+ })
228
+ end
229
+ return indexes.reverse
230
+ end
231
+
232
+ def next_page
233
+ Subject.new(@base_url, (@log < 1) ? fetch_subjects(@base_url).last : @log)
234
+ end
235
+ alias_method :next, :next_page
236
+
237
+ def prev_page
238
+ Subject.new(@base_url, (fetch_subjects(@base_url).size <= @log+1) ? 0 : @log)
239
+ end
240
+ alias_method :prev, :prev_page
241
+
242
+ def latest_log
243
+ fetch_subjects(@base_url).last
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,3 @@
1
+ class Megalith
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/megalith/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Oame"]
6
+ gem.email = ["oame@oameya.com"]
7
+ gem.description = %q{Megalith Parser for Ruby 1.9.x.}
8
+ gem.summary = %q{Megalith Parser for Ruby}
9
+ gem.homepage = "https://github.com/oame/megalith-ruby"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "megalith"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Megalith::VERSION
17
+ end
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require "pp"
4
+ require "spec_helper"
5
+
6
+ describe Megalith, "が #get, :log => 0 を呼ぶ時は" do
7
+ before do
8
+ megalith = Megalith.new("http://coolier.sytes.net:8080/sosowa/ssw_l/")
9
+ @subject = megalith.get :log => 0
10
+ end
11
+
12
+ it "Megalith::Subjectを返すこと" do
13
+ @subject.class.should == Megalith::Subject
14
+ end
15
+
16
+ it "最初のノベルはMegalith::Indexであること" do
17
+ @subject.first.class.should == Megalith::Index
18
+ end
19
+
20
+ it "最初のタイトルがStringであること" do
21
+ @subject.first.title.class.should == String
22
+ end
23
+
24
+ it "#next_pageがMegalith::Subjectを返すこと" do
25
+ @subject.next_page.class.should == Megalith::Subject
26
+ end
27
+
28
+ it "#prev_pageがMegalith::Subjectを返すこと" do
29
+ @subject.next_page.prev_page.class.should == Megalith::Subject
30
+ end
31
+
32
+ it "#latest_logがFixnumを返すこと" do
33
+ @subject.latest_log.class.should == Fixnum
34
+ end
35
+
36
+ it "最初を#fetchしたらMegalith::Novelを返すこと" do
37
+ @subject.first.fetch.class.should == Megalith::Novel
38
+ end
39
+
40
+ it "最初を#fetchしたMegalith::Novel#titleがStringなこと" do
41
+ @subject.first.fetch.title.class.should == String
42
+ end
43
+
44
+ it "直接Novelを取得出来ること" do
45
+ log = @subject.first.log
46
+ key = @subject.first.key
47
+ megalith = Megalith.new("http://coolier.sytes.net:8080/sosowa/ssw_l/")
48
+ novel = megalith.get :log => log, :key => key
49
+ novel.class.should == Megalith::Novel
50
+ end
51
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require "rspec"
4
+ require "megalith"
5
+
6
+ RSpec.configure do |config|
7
+ config.color_enabled = true
8
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: megalith
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Oame
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-23 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Megalith Parser for Ruby 1.9.x.
15
+ email:
16
+ - oame@oameya.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - .rspec
23
+ - .travis.yml
24
+ - Gemfile
25
+ - LICENSE
26
+ - README.md
27
+ - Rakefile
28
+ - lib/megalith.rb
29
+ - lib/megalith/essentials.rb
30
+ - lib/megalith/scheme.rb
31
+ - lib/megalith/version.rb
32
+ - megalith.gemspec
33
+ - spec/megalith_spec.rb
34
+ - spec/spec_helper.rb
35
+ homepage: https://github.com/oame/megalith-ruby
36
+ licenses: []
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 1.8.24
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: Megalith Parser for Ruby
59
+ test_files:
60
+ - spec/megalith_spec.rb
61
+ - spec/spec_helper.rb