comer_de_tapas 0.1.0

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: 52d7624ee230325d84d34d1d7dbed242eff3f67c
4
+ data.tar.gz: 821ec2bcb59323e569227d7996bf751a77e09a2b
5
+ SHA512:
6
+ metadata.gz: 0e13a238ba77729967bafa0c02f20f5352f0bf0b243bcecaee12249163504c463110d9ad4c26fe8e1a98e4ecfefa3b034e159308d9772d938fd99a33414215b1
7
+ data.tar.gz: 524d6b69a68edbeac46176d4ec624cfdb2a36bd9fc0488c4cc5822f9a31581ace50d1da03d8a365af02440a6e90673e9426acac33e66153ebdcc57b8d52366bd
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,41 @@
1
+ ## Contributing
2
+
3
+ **Everyone** is encouraged to help improve this project.
4
+
5
+ Ways to contribute:
6
+
7
+ * by reporting bugs
8
+ * by suggesting new features
9
+ * by writing or editing documentation
10
+ * by writing code (**no patch is too small**: fix typos, add comments, clean up
11
+ inconsistent whitespace)
12
+ * by refactoring code
13
+ * by fixing [issues][]
14
+ * by reviewing patches
15
+
16
+ [issues]: https://github.com/juanitofatas/comer_de_tapas/issues
17
+
18
+ ## Submit an Issue
19
+
20
+ We use the [GitHub issue tracker][issues] to track bugs and features. Before
21
+ submitting a bug report or feature request, check to make sure it hasn't
22
+ already been submitted. When submitting a bug report, please include a [Gist][]
23
+ that includes a stack trace and any details that may be necessary to reproduce
24
+ the bug, including your gem version, Ruby version, and operating system.
25
+ Ideally, a bug report should include a pull request with failing specs.
26
+
27
+ [gist]: https://gist.github.com/
28
+
29
+ ## Submit a Pull Request
30
+
31
+ 1. [Fork the repository.][fork]
32
+ 2. [Create a topic branch.][branch]
33
+ 3. Add tests for your unimplemented feature or bug fix.
34
+ 4. Implement your feature or bug fix.
35
+ 5. Run `rake test`. If your tests pass, go to step 6.
36
+ 6. Add, commit, and push your changes.
37
+ 7. [Submit a pull request.][pr]
38
+
39
+ [fork]: http://help.github.com/fork-a-repo/
40
+ [branch]: http://learn.github.com/p/branching.html
41
+ [pr]: http://help.github.com/send-pull-requests/
data/DEVELOPMENT.md ADDED
@@ -0,0 +1,15 @@
1
+ Development
2
+ ===========
3
+
4
+ Install all dependencies:
5
+
6
+ $ bundle install
7
+
8
+ Run the test:
9
+
10
+ $ rake
11
+
12
+ TODO
13
+ ----
14
+
15
+ * Figure out how to test using latest Minitest `>= 5.3.4`.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Juanito Fatas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ Comer de Tapas
2
+ ==============
3
+
4
+ [Ruby Tapas](http://www.rubytapas.com/) Downloader episodes for subscribers.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ $ gem install comer_de_tapas
10
+
11
+ Preparation
12
+ -----------
13
+
14
+ $ comer_de_tapas init
15
+
16
+ This will create a directory `~/.rubytapas` And a yaml `~/.rubytapas/.credentials`.
17
+
18
+ Please fill in your subscription information in `~/.rubytapas/.credentials`.
19
+
20
+ Example:
21
+
22
+ ```yaml
23
+ ---
24
+ credentials:
25
+ - email: foo@example.com
26
+ - password: password
27
+ - save_path: ~/Downloads
28
+ ```
29
+
30
+ If you want to save all Ruby Tapas episodes in your home folder. Please write it explicily as: `/Users/YOUR-USER-NAME`, please do not write `~`, because in Ruby, `~` considered as `nil` in YAML.
31
+
32
+ Usage
33
+ -----
34
+
35
+ $ comer_de_tapas download
36
+
37
+ Will fetch all episodes, then start to download it.
38
+
39
+ By default it will save a `~/.rubytapas/episodes.json`, to cache all episode attachment links for 3 days.
40
+
41
+ Why 3 days? Because normally our Chef Avdi ships new episode in 3.75 days on average.
42
+
43
+ But if Avdi ships within < 3 days, you can force it to get latest episodes:
44
+
45
+ $ comer_de_tapas download --force # or `-f`.
46
+
47
+ Command References
48
+ ------------------
49
+
50
+ | command | purpose | Options |
51
+ | ----------------------------- | ----------------------------------|---------|
52
+ | comer_de_tapas init | Initialize ComerDeTapas. | |
53
+ | comer_de_tapas download | Download episodes. | `-f` |
54
+ | comer_de_tapas version | Display version of Comer de Tapas | |
55
+
56
+ Similar Tools
57
+ -------------
58
+
59
+ * [bf4/downloader](https://github.com/bf4/downloader)
60
+ * [leafac/ruby-tapas-downloader](https://github.com/leafac/ruby-tapas-downloader)
61
+ * [xpepper/download_rubytapas.rb](https://gist.github.com/xpepper/5872399)
62
+ * [ebarendt/tapas](https://github.com/ebarendt/tapas)
63
+ * [YaronWittenstein/next-rubytapas](https://github.com/YaronWittenstein/next-rubytapas)
64
+ * [cibernox/rubytapas_downloader](https://github.com/cibernox/rubytapas_downloader)
65
+
66
+ Questions
67
+ ---------
68
+
69
+ Feel free to [open an issue](https://github.com/juanitofatas/comer_de_tapas/issues/new).
70
+
71
+ Development
72
+ -----------
73
+
74
+ Please see [DEVELOPMENT](/DEVELOPMENT.md) and [CONTRIBUTING](/CONTRIBUTING.md).
75
+
76
+ If you like this small tool, please give it a tweet!
77
+
78
+ License
79
+ -------
80
+
81
+ MIT License. Please see [LICENSE](/LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task default: :test
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Signal.trap('INT') { abort }
4
+ require 'comer_de_tapas'
5
+ ComerDeTapas::CLI.start(ARGV)
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "comer_de_tapas/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "comer_de_tapas"
8
+ spec.version = ComerDeTapas::VERSION
9
+ spec.authors = ["Juanito Fatas"]
10
+ spec.email = ["katehuang0320@gmail.com"]
11
+ spec.summary = %q{Ruby Tapas Episode Downloader.}
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/juanitofatas/comer_de_tapas"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = %w[CONTRIBUTING.md DEVELOPMENT.md LICENSE README.md Rakefile comer_de_tapas.gemspec]
17
+ spec.files += Dir.glob("lib/**/*.rb")
18
+ spec.files += Dir.glob("bin/**/*")
19
+ spec.files += Dir.glob("test/**/*")
20
+
21
+ spec.executables = ["comer_de_tapas"]
22
+ spec.test_files = Dir.glob("test/**/*")
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "thor"
26
+ spec.add_dependency "http", ">= 0.6"
27
+ spec.add_dependency "nokogiri"
28
+ spec.add_dependency "celluloid-io"
29
+ end
@@ -0,0 +1,33 @@
1
+ require 'thor'
2
+
3
+ module ComerDeTapas
4
+ class CLI < Thor
5
+ def initialize(*)
6
+ @client = Client.new
7
+ super
8
+ end
9
+
10
+ desc 'version', 'Show version'
11
+ def version
12
+ say VERSION
13
+ end
14
+ map %w[-v --version] => :version
15
+
16
+ desc 'init', 'Create config folder and files'
17
+ def init
18
+ @client.init!
19
+ say 'Please fill in your subscription info in ~/.rubytapas/.credentials'
20
+ end
21
+
22
+ # -f, --force, options[:force] => true, otherwise nil.
23
+ desc 'download', 'Download RubyTapas episodes'
24
+ method_option 'force', :aliases => '-f', type: :boolean, desc: 'Force download.'
25
+ def download
26
+ @client.fetch_episodes!(options[:force])
27
+ @client.prepare_save_folder!
28
+ @client.authenticate
29
+ @client.load_episodes
30
+ @client.download_all_tapas!
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,207 @@
1
+ require 'http'
2
+ require 'json'
3
+ require 'pathname'
4
+ require 'fileutils'
5
+
6
+ module ComerDeTapas
7
+ class Client
8
+
9
+ # Initialize comer de tapas
10
+ # $ mkdir -p ~/.rubytapas/
11
+ # $ touch ~/.rubytapas/.credentials
12
+ def init!
13
+ if File.exist?(RUBYTAPAS_DIR) && File.exist?(CREDENTIAL_FILE)
14
+ abort 'Credentials found. type `comer_de_tapas download` to download.'
15
+ end
16
+ create_rubytapas_files!
17
+ puts '~/.rubytapas/.credentials folder and file has been created.'
18
+ end
19
+
20
+ # Fetch latest feed on rubytapas.dpdcart.com
21
+ # Parse it to episode, save episodes data as json to ~/.rubytapas.json
22
+ def fetch_episodes! force=nil
23
+ return puts 'Use cached episode data.' if fresh? && force.nil?
24
+ puts 'Fetching episodes...'
25
+ get_feed_with_basic_auth
26
+ save_feed_data parse_xml_feed
27
+ puts 'Episodes successfully fetched.'
28
+ end
29
+
30
+ # Create user specified folder: credentials[:save_path]
31
+ def prepare_save_folder!
32
+ return puts "#{save_folder} found." if File.exist? save_folder
33
+
34
+ FileUtils.mkdir_p save_folder.expand_path
35
+ puts "#{save_folder} created."
36
+ end
37
+
38
+ # Authenticate and return Cookie
39
+ def authenticate
40
+ @cookie ||= HTTP.post(LOGIN_URL, form_params).headers['Set-Cookie']
41
+ end
42
+
43
+ # Load episodes json from EPISODES_JSON_FILE
44
+ def load_episodes
45
+ @episodes ||= JSON.parse(File.read EPISODES_JSON_FILE)
46
+ end
47
+
48
+ # User spefified folder to save episodes.
49
+ # @return [Pathname]
50
+ def save_folder
51
+ Pathname credentials[:save_path]
52
+ end
53
+
54
+ # Download episode in parallel using Actors
55
+ # Powered by Celluloid::IO
56
+ def download_all_tapas!
57
+ episodes.each do |episode|
58
+ FileUtils.cd(save_folder.expand_path) do
59
+ episode_title = episode['title']
60
+ puts "Downloading Epsiode #{episode_title}..."
61
+
62
+ episode_folder = save_folder.join(sanitized episode_title).expand_path
63
+
64
+ FileUtils.mkdir_p episode_folder unless File.exist? episode_folder
65
+
66
+ FileUtils.cd episode_folder do
67
+ fetcher = Fetcher.new
68
+ file_and_links = episode['links']
69
+ downloadables = find_downloadables file_and_links
70
+
71
+ if downloadables.all? &:nil?
72
+ puts 'Already downloaded, skip.'
73
+ next
74
+ end
75
+
76
+ download_parallelly! downloadables
77
+ puts "Episode #{episode_title} content all saved."
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ attr_reader :feed_xml, :cookie, :episodes
86
+
87
+ # Download episode all attachments
88
+ # compact to remove attachment that already downloaded
89
+ # @param [Array] downloadables
90
+ def download_parallelly! downloadables
91
+ downloadables.compact.each do |file, future|
92
+ response = future.value.to_s
93
+ puts "Downloading #{file}..."
94
+ IO.write file, response
95
+ puts "#{file} saved."
96
+ end
97
+ end
98
+
99
+ # Find episode's attachment that has not been downloaded
100
+ # @param [Array] file_and_links
101
+ def find_downloadables file_and_links
102
+ file_and_links.map do |file_and_link|
103
+ next if File.exist? file_and_link['filename']
104
+
105
+ q, v = file_and_link['link'].split('?').last.split('=')
106
+ [file_and_link['filename'], fetcher.future.fetch(DOWNLOAD_URL, cookie, { q => v })]
107
+ end
108
+ end
109
+
110
+ # mkdir -p ~/.rubytapas
111
+ # touch ~/.rubytapas/.credentials
112
+ def create_rubytapas_files!
113
+ FileUtils.mkdir_p RUBYTAPAS_DIR
114
+ FileUtils.touch CREDENTIAL_FILE
115
+ IO.write CREDENTIAL_FILE, credential_template
116
+ end
117
+
118
+ # Use to create empty credential file
119
+ def credential_template
120
+ require 'yaml'
121
+ {"credentials"=>[{"email"=>nil}, {"password"=>nil}, {"save_path"=>nil}]}.to_yaml
122
+ end
123
+
124
+ # Get raw feed data (XML), RSS
125
+ def get_feed_with_basic_auth
126
+ puts 'Authorizing...'
127
+ @feed_xml = HTTP.auth(:basic, authenticate_params).get(FEED_URL).body.to_s
128
+ puts 'Authroized.'
129
+ end
130
+
131
+ # Params for basic authentication
132
+ def authenticate_params
133
+ { user: credentials[:email], pass: credentials[:password] }
134
+ end
135
+
136
+ # RubyTapas subscription credentials (~/.rubytapas/.credentials)
137
+ # @return [Hash]
138
+ def credentials
139
+ Subscription.new.to_h
140
+ end
141
+
142
+ # Parse raw feed data (XML), retrive episode's title and links.
143
+ # @return [Array<Hash>]
144
+ def parse_xml_feed
145
+ puts 'Parsing Episodes...'
146
+ require 'nokogiri'
147
+ items = Nokogiri::XML(feed_xml).xpath('//item')
148
+
149
+ epsiode_data = items.map do |item|
150
+ children = item.children
151
+
152
+ title = (children / 'title').first.child.content
153
+ description = (children / 'description').first.child.content
154
+
155
+ links = Nokogiri::HTML(description).css('ul li a')
156
+
157
+ { title: title, links: attachments(links) }
158
+ end
159
+
160
+ puts 'Episodes parsed successfully.'
161
+
162
+ return epsiode_data
163
+ end
164
+
165
+ # Given links, parse to
166
+ # { filename: "123.rb", "/subscriber/download?file_id=34567" }
167
+ # @return [Array<Hash>]
168
+ def attachments links
169
+ links.each_with_object([]) do |link, episode|
170
+ if link['href'] =~ /rubytapas.dpdcart.com\/subscriber\/download/
171
+ episode << { filename: link.content, link: link['href'].gsub(/#{BASE_URL}/, '') }
172
+ end
173
+ end
174
+ end
175
+
176
+ # Write episodes data to ~/.rubytapas/episodes.json
177
+ def save_feed_data feed
178
+ puts 'Saving episodes data to ~/.rubytapas/episodes.json...'
179
+ IO.write EPISODES_JSON_FILE, feed.to_json
180
+ puts 'Saved.'
181
+ end
182
+
183
+ # Return each episode's folder name
184
+ def sanitized title
185
+ dasherize_file_name(title)
186
+ end
187
+
188
+ # Before: 999 Array.first, Foo::Bar, Class<<self
189
+ # After: 999-array-first-foo-bar-class<<self
190
+ def dasherize_file_name file_name
191
+ file_name.downcase.gsub('&lt;', '<').gsub(/[^\w<>#?!$]+/, '-')
192
+ end
193
+
194
+ # Form params to post for HTTP
195
+ # @return [Hash]
196
+ def form_params
197
+ { form: { username: credentials[:email], password: credentials[:password] } }
198
+ end
199
+
200
+ # If the episodes json was made of 259_200.seconds.ago (3 days)
201
+ # @return [Boolean] true if episodes.json creation time < 3 days
202
+ def fresh?
203
+ return false unless File.exist? EPISODES_JSON_FILE
204
+ Time.now - File.ctime(EPISODES_JSON_FILE) < 259_200
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,12 @@
1
+ require 'pathname'
2
+
3
+ module ComerDeTapas
4
+ BASE_URL = 'https://rubytapas.dpdcart.com'
5
+ DOWNLOAD_URL = BASE_URL + '/subscriber/download'
6
+ LOGIN_URL = BASE_URL + '/subscriber/login'
7
+ FEED_URL = BASE_URL + '/feed'
8
+
9
+ RUBYTAPAS_DIR = Pathname.new(ENV['HOME']).join('.rubytapas')
10
+ EPISODES_JSON_FILE = RUBYTAPAS_DIR.join('episodes.json')
11
+ CREDENTIAL_FILE = RUBYTAPAS_DIR.join('.credentials')
12
+ end
@@ -0,0 +1,16 @@
1
+ require 'celluloid/io'
2
+
3
+ module ComerDeTapas
4
+ class Fetcher
5
+ include Celluloid::IO
6
+
7
+ # Fetch url with given cookie, and query string (optional)
8
+ # @param [String] url
9
+ # @param cookie
10
+ # @option query [Hash]
11
+ def fetch url, cookie, query={}
12
+ require 'http'
13
+ HTTP.with('Cookie' => cookie).get(url, ssl_socket_class: Celluloid::IO::SSLSocket, params: query)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,65 @@
1
+ module ComerDeTapas
2
+ class Subscription
3
+ CredentialYamlNotExist = Class.new StandardError
4
+ CredentialYamlKeyError = Class.new StandardError
5
+ CredentialYamlValueError = Class.new StandardError
6
+
7
+ def initialize
8
+ raise CredentialYamlNotExist, 'Please run `comer_de_tapas init` first' unless File.exist? CREDENTIAL_FILE
9
+
10
+ set_subscription_data if subscription_data_valid?
11
+ end
12
+
13
+ # @return [Hash] User's Ruby Tapas credential information
14
+ def to_h
15
+ { email: email, password: password, save_path: save_path }
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :email, :password, :save_path
21
+
22
+ # Load ~/.rubytapas/.credentials yaml
23
+ def load_credential_data
24
+ require 'yaml'
25
+ @credential_yaml ||= YAML.load_file CREDENTIAL_FILE
26
+ end
27
+
28
+ # Check if ~/.rubytapas/.credentials files are filled and corrected.
29
+ def subscription_data_valid?
30
+ # empty credential file's size is about 50-55.
31
+ # 65 is when you have a very short email, password, and save_path.
32
+ # So when you filled in data, probably will > 65.
33
+ if File.size(CREDENTIAL_FILE) < 65
34
+ puts "Did you fill in your subscription data in #{CREDENTIAL_FILE}?"
35
+ return false
36
+ end
37
+
38
+ credential_data_valid?(get_validate load_credential_data)
39
+ end
40
+
41
+ # Check if credential data valid?
42
+ def credential_data_valid? data
43
+ data.each do |hash|
44
+ hash.each do |k,v|
45
+ raise CredentialYamlKeyError, "Valid yaml keys: #{KEYS.join(' ,')}." unless %w(email password save_path).include? k
46
+ raise CredentialYamlValueError, "Please fill value for this one: #{k}" if v.nil?
47
+ end
48
+ end
49
+
50
+ return true
51
+ end
52
+
53
+ # Get credential data from loaded yaml for validation.
54
+ def get_validate data
55
+ data.values.flatten
56
+ end
57
+
58
+ # Set subscription data from ~/.rubytapas/.credentials yaml
59
+ def set_subscription_data
60
+ @email ||= load_credential_data['credentials'][0]['email']
61
+ @password ||= load_credential_data['credentials'][1]['password']
62
+ @save_path ||= load_credential_data['credentials'][2]['save_path']
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module ComerDeTapas
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ require "comer_de_tapas/version"
2
+ require "comer_de_tapas/constants"
3
+ require "comer_de_tapas/subscription"
4
+ require "comer_de_tapas/fetcher"
5
+ require "comer_de_tapas/client"
6
+ require "comer_de_tapas/cli"
7
+
8
+ module ComerDeTapas
9
+ end
data/test/cli_test.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ class CliTest < ComerDeTapas::Test
4
+ def setup
5
+ @cli = ComerDeTapas::CLI.new
6
+ end
7
+
8
+ def test_cli_version
9
+ out, _ = capture_io { @cli.version }
10
+ assert_match %r(\d.\d.\d), out
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class ClientTest < ComerDeTapas::Test
4
+ def setup
5
+ @client = ComerDeTapas::Client.new
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class RubyTapasFetcherTest < ComerDeTapas::Test
4
+ def setup
5
+ @fetch = ComerDeTapas::Fetcher.new
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ class SubscriptionTest < ComerDeTapas::Test
4
+ def setup
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../lib/comer_de_tapas'
2
+
3
+ # ensures using the gem, and not the built-in.
4
+ gem 'minitest'
5
+ require 'minitest/autorun'
6
+
7
+ module ComerDeTapas
8
+ class Test < Minitest::Test
9
+ end
10
+ end
11
+
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: comer_de_tapas
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Juanito Fatas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: http
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: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: celluloid-io
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Ruby Tapas Episode Downloader.
70
+ email:
71
+ - katehuang0320@gmail.com
72
+ executables:
73
+ - comer_de_tapas
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - CONTRIBUTING.md
78
+ - DEVELOPMENT.md
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - bin/comer_de_tapas
83
+ - comer_de_tapas.gemspec
84
+ - lib/comer_de_tapas.rb
85
+ - lib/comer_de_tapas/cli.rb
86
+ - lib/comer_de_tapas/client.rb
87
+ - lib/comer_de_tapas/constants.rb
88
+ - lib/comer_de_tapas/fetcher.rb
89
+ - lib/comer_de_tapas/subscription.rb
90
+ - lib/comer_de_tapas/version.rb
91
+ - test/cli_test.rb
92
+ - test/client_test.rb
93
+ - test/fetcher_test.rb
94
+ - test/subscription_test.rb
95
+ - test/test_helper.rb
96
+ homepage: https://github.com/juanitofatas/comer_de_tapas
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.3.0
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Ruby Tapas Episode Downloader.
120
+ test_files:
121
+ - test/cli_test.rb
122
+ - test/client_test.rb
123
+ - test/fetcher_test.rb
124
+ - test/subscription_test.rb
125
+ - test/test_helper.rb
126
+ has_rdoc: