manga-tools 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbd23ebbac4de4066358e4f01d81465f87fea705f324dc3de5e4984a61248ab6
4
- data.tar.gz: 652062faa457e12a19d5e19baad357483697a2aa1c50c7f1b42b4f141ea39235
3
+ metadata.gz: b4e6fa4035509554d7e20e8a8eba9c21b813bb8e68dc800b3c44a58419dfa2e0
4
+ data.tar.gz: 1ae99cc528222dcad3a93cfb36cc34ec86474a157a642f51223ff5b7daa082ac
5
5
  SHA512:
6
- metadata.gz: 0276b8fb60c70d5d7e3de81c8d3678e4b7ad165668ddaab36570a07e7492b0f1962920ef9887cb3bee8ec5084d3ad414e8407cd361e34d9b0400de506d46566a
7
- data.tar.gz: 43344b6b8dbe7d75f9316f0870fa4feb2c1fa8ae127bb3ad3dd72969bb1252d0a3c71b36ecbe7ed84b36ddae58b18df90580493abfeb077a9ac43cb5e1c78c4f
6
+ metadata.gz: 58d66eea0fd9957cb9a2a563810b4397fb0d476b6d99a7f56b4a3668a22cea0351aa3eca8758d5bf267a04eb7b34c842340ed9e42875750f973eb164157df91e
7
+ data.tar.gz: a61b64bbf848a173b45a16698e6a7cc7da586a13c0a7c681ebc75555ea958421d3327541258f4b2ea989d5501234df94fb0b3c443be7d43769b775a02fd4b394
@@ -0,0 +1,12 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
+ patreon: yagihiro
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ otechie: # Replace with a single Otechie username
12
+ custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
@@ -19,11 +19,17 @@ AllCops:
19
19
  Exclude:
20
20
  - 'bin/*'
21
21
 
22
+ Lint/AmbiguousBlockAssociation:
23
+ Exclude:
24
+ - 'spec/**/*'
25
+
22
26
  Metrics/AbcSize:
23
27
  Max: 37
24
28
 
25
29
  Metrics/BlockLength:
26
30
  Max: 36
31
+ Exclude:
32
+ - 'spec/**/*'
27
33
 
28
34
  Metrics/CyclomaticComplexity:
29
35
  Max: 10
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- manga-tools (0.1.3)
4
+ manga-tools (0.2.0)
5
5
  faraday (~> 1.0)
6
6
  thor (~> 1.0)
7
7
 
data/README.md CHANGED
@@ -29,6 +29,18 @@ Or install it yourself as:
29
29
  $ manga-tools search "ONE PIECE"
30
30
  ```
31
31
 
32
+ * Follow the specified title
33
+
34
+ ```
35
+ $ manga-tools follow "key"
36
+ ```
37
+
38
+ * Displays a list of the titles you are following
39
+
40
+ ```
41
+ $ manga-tools follow-list
42
+ ```
43
+
32
44
  ## Development
33
45
 
34
46
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'tools/cli'
4
+ require_relative 'tools/client'
5
+ require_relative 'tools/formatter'
4
6
  require_relative 'tools/http'
7
+ require_relative 'tools/session'
8
+ require_relative 'tools/session_store'
5
9
  require_relative 'tools/version'
6
10
 
7
11
  module Manga
@@ -2,27 +2,41 @@
2
2
 
3
3
  require 'json'
4
4
  require 'thor'
5
- require_relative 'http'
5
+ require_relative 'client'
6
+ require_relative 'formatter'
6
7
 
7
8
  module Manga
8
9
  module Tools
9
10
  # CLI class
10
11
  class CLI < Thor
12
+ HOST_OPTION = { aliases: '-h', desc: 'Specifies the host to connect to for development' }.freeze
13
+
11
14
  def self.exit_on_failure?
12
15
  true
13
16
  end
14
17
 
15
18
  desc 'search WORD', 'Search titles for a given WORD'
19
+ method_option :host, HOST_OPTION
16
20
  def search(word)
17
- url = "https://manga-tools-server.herokuapp.com/publications?keyword=#{CGI.escape(word)}"
18
- res = Manga::Tools::Http.get(url)
19
- results = JSON.parse(res.body)
21
+ client = Manga::Tools::Client.new
22
+ results = client.search(word, options)
23
+ Manga::Tools::Formatter.display(:search, word, results)
24
+ end
25
+
26
+ desc 'follow KEY', 'Follow a title for a given follow KEY'
27
+ method_option :host, HOST_OPTION
28
+ def follow(key)
29
+ client = Manga::Tools::Client.new
30
+ results = client.follow(key, options)
31
+ Manga::Tools::Formatter.display(:follow, key, results)
32
+ end
20
33
 
21
- puts "Searching '#{word}' ..."
22
- results.each do |item|
23
- puts "#{item['published_at']}: #{item['title']}"
24
- end
25
- puts 'Finished.'
34
+ desc 'follow-list', 'Displays the follow list'
35
+ method_option :host, HOST_OPTION
36
+ def follow_list
37
+ client = Manga::Tools::Client.new
38
+ results = client.follow_list(options)
39
+ Manga::Tools::Formatter.display(:follow_list, results)
26
40
  end
27
41
  end
28
42
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+ require 'json'
5
+ require_relative 'http'
6
+ require_relative 'session'
7
+
8
+ module Manga
9
+ module Tools
10
+ # Client Application class
11
+ class Client
12
+ # @return [Manga::Tools::Session] a session instance
13
+ attr :session
14
+
15
+ def initialize
16
+ @session = Manga::Tools::Session.new
17
+ end
18
+
19
+ # Search `word` with options.
20
+ # @param word [String] search string
21
+ # @param options [Hash] command options from Thor
22
+ def search(word, options)
23
+ session.options = adapt_to_dev_env(options)
24
+ session.get("/publications?keyword=#{CGI.escape(word)}")
25
+ end
26
+
27
+ # Follow a title for a given follow `key`
28
+ # @param key [String] follow key
29
+ # @param options [Hash] command options from Thor
30
+ def follow(key, options)
31
+ params = { key: key }
32
+ session.options = adapt_to_dev_env(options)
33
+ session.post('/follows', params)
34
+ end
35
+
36
+ # Displays the follow list
37
+ # @param options [Hash] command options from Thor
38
+ def follow_list(options)
39
+ session.options = adapt_to_dev_env(options)
40
+ session.get('/follows')
41
+ end
42
+
43
+ private
44
+
45
+ def adapt_to_dev_env(options)
46
+ opts = options.dup
47
+
48
+ if opts[:host]
49
+ # If the `host` option is specified, it is assumed to be the development environment
50
+ opts[:session_file_name] = 'session-development.txt'
51
+ end
52
+
53
+ opts
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Manga
4
+ module Tools
5
+ # Formatter class
6
+ class Formatter
7
+ class << self
8
+ def display(command, *results)
9
+ case command
10
+ when :search
11
+ display_search(results)
12
+ when :follow
13
+ display_follow(results)
14
+ when :follow_list
15
+ display_follow_list(results)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def display_search(results)
22
+ puts "Searching '#{results[0]}' ..."
23
+ results[1].each do |item|
24
+ puts "#{item['published_at']} [#{item['follow_key']}]: #{item['title']}"
25
+ end
26
+ puts 'Finished.'
27
+ end
28
+
29
+ def display_follow(results)
30
+ puts "Followed '#{results[1]['title']}'."
31
+ puts 'Finished.'
32
+ end
33
+
34
+ def display_follow_list(results)
35
+ puts 'Listing follow list...'
36
+ results[0].each do |item|
37
+ puts (item['title']).to_s
38
+ end
39
+ puts 'Finished.'
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -9,35 +9,48 @@ module Manga
9
9
  # HTTP client class
10
10
  module Http
11
11
  # @param url [String] an url string, eg: `https://example.com`
12
+ # @param session_id [String, nil] A Session ID string or nil
12
13
  # @return [Faraday::Connection] a connection object
13
- def self.connection(url)
14
- @connection ||= Faraday.new(
15
- url: url,
16
- headers: { 'User-Agent' => user_agent }
17
- ) do |f|
14
+ def self.connection(url, session_id)
15
+ headers = { 'User-Agent' => user_agent }
16
+ headers['X-Session-ID'] = session_id if session_id
17
+
18
+ @connection = Faraday.new(url: url, headers: headers) do |f|
18
19
  # f.response :logger
20
+ f.response :raise_error
19
21
  end
20
22
  end
21
23
 
22
24
  # @param url [String] an url string, eg: `https://example.com/path/to/object`
25
+ # @param session_id [String, nil] A Session ID string or nil
23
26
  # @return [Faraday::Response] a response object
24
- def self.get(url)
27
+ def self.get(url, session_id)
25
28
  u = URI.parse(url)
26
- connection("#{u.scheme}://#{u.host}").get(u.request_uri)
29
+ connection(connection_url(u), session_id).get(u.request_uri)
27
30
  end
28
31
 
29
- # @param response [Faraday::Response] a response object
30
- # @return [nil|Integer] number of second to cache
31
- #
32
- # supported http header
33
- # - cache-control: max-age=[sec]
34
- def self.seconds_to_cache(response)
35
- result = response['cache-control']&.split(/,/)&.map(&:strip)&.find { |item| item =~ /max-age=(.+)/ }
36
- return nil unless result
32
+ def self.post(url, session_id, params)
33
+ u = URI.parse(url)
34
+ connection(connection_url(u), session_id).post do |req|
35
+ req.headers['Content-Type'] = 'application/json'
36
+ req.url u.request_uri
37
+ req.body = params.to_json
38
+ end
39
+ end
37
40
 
38
- Regexp.last_match(1).to_i
41
+ # @param url [URI] A URL instance.
42
+ # @return [String] Returns the URL to connect to.
43
+ #
44
+ # If the port is not a standard port (80 or 443), the port number is included.
45
+ def self.connection_url(url)
46
+ if [80, 443].include?(url.port)
47
+ "#{url.scheme}://#{url.host}"
48
+ else
49
+ "#{url.scheme}://#{url.host}:#{url.port}"
50
+ end
39
51
  end
40
52
 
53
+ # @return [String] Returns a user agent string
41
54
  def self.user_agent
42
55
  @user_agent ||= "manga-tools #{Manga::Tools::VERSION}"
43
56
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'http'
5
+ require_relative 'session_store'
6
+
7
+ module Manga
8
+ module Tools
9
+ # Network Session class (Session ID handling + HTTP CRUD handling)
10
+ class Session
11
+ DEFAULT_HOST = 'https://manga-tools-server.herokuapp.com'
12
+
13
+ # @return [Hash] options hash instance
14
+ attr :options
15
+
16
+ # @return [SessionStore] the session store instance
17
+ attr :store
18
+
19
+ def initialize
20
+ @store = Manga::Tools::SessionStore.new
21
+ @options = {}
22
+ end
23
+
24
+ def options=(new_options)
25
+ @base_url = nil
26
+ @options = new_options
27
+ store.session_file_name = @options[:session_file_name] if @options[:session_file_name]
28
+ end
29
+
30
+ def get(path)
31
+ response = with_session { |session_id| Manga::Tools::Http.get(build_full_url(path), session_id) }
32
+ JSON.parse(response.body)
33
+ end
34
+
35
+ def post(path, params)
36
+ response = with_session { |session_id| Manga::Tools::Http.post(build_full_url(path), session_id, params) }
37
+ JSON.parse(response.body)
38
+ end
39
+
40
+ private
41
+
42
+ def with_session
43
+ session_id = store.load
44
+ res = yield session_id
45
+ session_id = res.headers['X-Session-ID']
46
+ store.store(session_id) if session_id
47
+ res
48
+ end
49
+
50
+ def base_url
51
+ @base_url ||= options[:host] ? "http://#{options[:host]}" : DEFAULT_HOST
52
+ end
53
+
54
+ def build_full_url(path)
55
+ "#{base_url}#{path}"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+
5
+ module Manga
6
+ module Tools
7
+ # A class on session retention.
8
+ class SessionStore
9
+ # @return [String] the session file name string
10
+ attr_writer :session_file_name
11
+
12
+ def initialize
13
+ create_session_dir_if_necessary
14
+ @session_file_name = 'session.txt'
15
+ end
16
+
17
+ # Store a session.
18
+ def store(session_id)
19
+ return if exists?
20
+
21
+ File.open(session_file_path, 'w') do |f|
22
+ f.write(session_id)
23
+ end
24
+ end
25
+
26
+ # @return [String, nil] Returns the session ID if the session is stored, otherwise it returns nil
27
+ def load
28
+ return nil unless exists?
29
+
30
+ File.read(session_file_path)
31
+ end
32
+
33
+ # @return [Boolean] true if the session exists, otherwise returns false.
34
+ def exists?
35
+ File.exist?(session_file_path)
36
+ end
37
+
38
+ # @return [String] the session file path
39
+ def session_file_path
40
+ "#{session_dir}/#{@session_file_name}"
41
+ end
42
+
43
+ private
44
+
45
+ # @return [String] the root directory
46
+ def root_dir
47
+ @root_dir ||= "#{Dir.home}/.manga-tools"
48
+ end
49
+
50
+ # @return [String] the session directory
51
+ def session_dir
52
+ @session_dir ||= "#{root_dir}/session"
53
+ end
54
+
55
+ def create_session_dir_if_necessary
56
+ FileUtils.mkdir_p(session_dir)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Manga
4
4
  module Tools
5
- VERSION = '0.1.3'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manga-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroki Yagita
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-22 00:00:00.000000000 Z
11
+ date: 2020-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -46,6 +46,7 @@ executables:
46
46
  extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
+ - ".github/FUNDING.yml"
49
50
  - ".github/workflows/ruby.yml"
50
51
  - ".gitignore"
51
52
  - ".rspec"
@@ -63,7 +64,11 @@ files:
63
64
  - exe/manga-tools
64
65
  - lib/manga/tools.rb
65
66
  - lib/manga/tools/cli.rb
67
+ - lib/manga/tools/client.rb
68
+ - lib/manga/tools/formatter.rb
66
69
  - lib/manga/tools/http.rb
70
+ - lib/manga/tools/session.rb
71
+ - lib/manga/tools/session_store.rb
67
72
  - lib/manga/tools/version.rb
68
73
  - manga-tools.gemspec
69
74
  homepage: https://github.com/yagihiro/manga-tools