Skip to content
This repository has been archived by the owner on Mar 3, 2020. It is now read-only.

Commit

Permalink
Merge pull request #5 from RLovelett/vcr
Browse files Browse the repository at this point in the history
Create newer more robust version of iMasquerade gem.

[ci skip]
  • Loading branch information
RLovelett committed Nov 6, 2014
2 parents 4743364 + 6c3ab60 commit 3aa4f33
Show file tree
Hide file tree
Showing 14 changed files with 230 additions and 120 deletions.
3 changes: 3 additions & 0 deletions .rspec
@@ -0,0 +1,3 @@
--color
--require spec_helper
--format documentation
2 changes: 1 addition & 1 deletion .ruby-version
@@ -1 +1 @@
ruby-1.9.3-p392
2.1
3 changes: 2 additions & 1 deletion .travis.yml
@@ -1,4 +1,5 @@
rvm:
- 1.9.2
- 1.9.3
- 2.0.0
- 2.1
- ruby-head
13 changes: 6 additions & 7 deletions README.rdoc
Expand Up @@ -8,16 +8,15 @@ source feed url and is subsequently returned.

== Requirements

* uri
* curb => 0.7.10
* nokogiri => 1.4.4
* httparty
* multi_json

This project was built and tested against ruby 1.9.2p160 (2011-01-16 revision 30579) [x86_64-darwin10.6.0]
This project was built and tested against ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-darwin14.0.0]

== Usage

Imasquerade::Extractor.parse_itunes_uri("http://itunes.apple.com/us/podcast/the-f-u-sports-talk-podcast/id356478903")
# returns "http://www.urannonline.com/Collection_Site/The_F_U_Sports_Talk_Podcast/rss.xml"
Imasquerade.parse_itunes_uri("https://itunes.apple.com/us/podcast/wdw-radio-show-your-walt-disney/id215517191?mt=2")
# returns "http://www.wdwradio.com/xml/wdwradio.xml"

Technically, the parser can take the url in another format (e.g., id=356478903).
However I do not believe Apple is using this format any longer. Regardless the
Expand All @@ -35,6 +34,6 @@ capability is there.

== Copyright

Copyright (c) 2011 Ryan Lovelett. See LICENSE.txt for
Copyright (c) 2011-2014 Ryan Lovelett. See LICENSE.txt for
further details.

16 changes: 7 additions & 9 deletions Rakefile
@@ -1,11 +1,9 @@
require 'rake'
require 'rake/testtask'
require 'bundler/gem_tasks'
begin
require 'rspec/core/rake_task'

Rake::TestTask.new(:test) do |test|
test.libs << 'lib' << 'test'
test.pattern = 'test/**/test_*.rb'
test.verbose = true
end
RSpec::Core::RakeTask.new(:spec)

task :default => :test
task :default => :spec
rescue LoadError
# no rspec available
end
12 changes: 6 additions & 6 deletions imasquerade.gemspec
Expand Up @@ -16,10 +16,10 @@ Gem::Specification.new do |gem|
gem.require_paths = ["lib"]
gem.version = Imasquerade::VERSION

gem.add_dependency "curb"
gem.add_dependency "nokogiri"
gem.add_dependency "plist"
gem.add_dependency "colorize"
gem.add_development_dependency "rake"
gem.add_development_dependency "shoulda"
gem.add_dependency 'httparty', '~> 0.13.0'
gem.add_dependency 'multi_json', '~> 1.10.0'
gem.add_development_dependency 'rake', '~> 10.3.0'
gem.add_development_dependency 'rspec', '~> 3.1.0'
gem.add_development_dependency 'vcr', '~> 2.9.0'
gem.add_development_dependency 'webmock', '~> 1.20.0'
end
7 changes: 2 additions & 5 deletions lib/imasquerade.rb
@@ -1,10 +1,7 @@
$:.unshift(File.dirname(__FILE__)) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

require 'uri'
require 'curb'
require 'nokogiri'
require 'plist'
require 'colorize'
require 'httparty'
require 'multi_json'

require 'imasquerade/extractor'
72 changes: 10 additions & 62 deletions lib/imasquerade/extractor.rb
@@ -1,69 +1,17 @@
module Imasquerade
class Extractor
public
def Extractor.parse_itunes_uri(uri='')
return Extractor.fetch_and_parse_feed_from_apple(uri)
end
def Extractor.debug_output(uri='')
id = Extractor.itunes_id(uri)
doc = Extractor.get_raw_string(uri)
File.open("#{id}.xml", 'w') {|f| f.write(doc) }
end
private
def Extractor.uri_orig(id='')
# This is the original place to check
@@uri_orig = "http://itunes.apple.com/podcast/id#{id}"
end
@itunes_id_regex = /(?:id=?)(?<id>[0-9]+)/i

def Extractor.uri_redirect(id='')
# Check here if there is a redirect
@@uri_redirect = "http://itunes.apple.com/WebObjects/DZR.woa/wa/viewPodcast?id=#{id}"
end
def self.parse_itunes_uri(uri)
# Extract the iTunes id from the URI
id = uri.match(@itunes_id_regex)[:id]

def Extractor.itunes_id(url="")
/(?:id=?)([0-9]+)/i =~ url
return $1
end
# Get raw JSON search
response = HTTParty.get('https://itunes.apple.com/lookup', {query: {id: id}})

def Extractor.get_raw_string(uri="")
# In case there is some sort of error
begin
response = Curl::Easy.perform(uri) do |curl|
curl.headers["User-Agent"] = 'iTunes/10.1.1'
end
return response.body_str
rescue Nokogiri::XML::SyntaxError => e
puts "Caught exception: #{e}".colorize(:red)
return nil
rescue Curl::Err::HostResolutionError => e
puts "Caught exception: #{e}".colorize(:red)
return nil
rescue Curl::Err::RecvError => e
puts "Caught exception: #{e}".colorize(:red)
return nil
end
end
# Parse the JSON to a Hash
hash = MultiJson.load(response.body, symbolize_keys: true)

def Extractor.fetch_and_parse_feed_from_apple(url)
id = Extractor.itunes_id(url)
response = Extractor.get_raw_string(url)
reader = Nokogiri::XML(response)
feed_url = reader.xpath('//@feed-url')
return feed_url[0].value unless feed_url.count == 0
response.force_encoding("UTF-8") if response.encoding == Encoding::ASCII_8BIT
begin
list = Plist::parse_xml(response)
rescue RuntimeError => bang
list = {}
end
if list.has_key?('action') && list['action']['kind'] == "Goto" then
response = Extractor.fetch_and_parse_feed_from_apple(list['action']['url'])
return response
elsif list.has_key?('dialog')
throw list['dialog']['explanation']
end
File.open("#{id}.html", 'w') {|f| f.write(response) }
throw "The feed was either empty, or mal-formed."
end
# Extract the first feed URL
hash[:results].first[:feedUrl] if hash.has_key?(:results) && hash[:resultCount] > 0
end
end
2 changes: 1 addition & 1 deletion lib/imasquerade/version.rb
@@ -1,3 +1,3 @@
module Imasquerade
VERSION = "0.2.4"
VERSION = "0.3.0"
end
74 changes: 74 additions & 0 deletions spec/cassettes/itunes.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions spec/imasquerade_spec.rb
@@ -0,0 +1,17 @@
require 'spec_helper'

describe Imasquerade, vcr: {
cassette_name: 'itunes',
record: :new_episodes
} do
describe '.parse_itunes_uri' do
let(:uri) { 'https://itunes.apple.com/us/podcast/wdw-radio-show-your-walt-disney/id215517191?mt=2' }
let(:expected_response) { 'http://www.wdwradio.com/xml/wdwradio.xml' }

subject(:response) { Imasquerade.parse_itunes_uri(uri) }

it 'should perform the example in the README' do
expect(response).to eq(expected_response)
end
end
end
101 changes: 101 additions & 0 deletions spec/spec_helper.rb
@@ -0,0 +1,101 @@
require 'webmock/rspec'
require 'vcr'

require 'imasquerade'

# This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause this
# file to always be loaded, without a need to explicitly require it in any files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need it.
#
# The `.rspec` file also contains a few flags that are not defaults but that
# users commonly want.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end

# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end

# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Limits the available syntax to the non-monkey patched syntax that is recommended.
# For more details, see:
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
config.disable_monkey_patching!
# This setting enables warnings. It's recommended, but in some cases may
# be too noisy due to issues in dependencies.
config.warnings = true
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end

VCR.configure do |c|
c.cassette_library_dir = 'spec/cassettes'
c.hook_into :webmock
# c.preserve_exact_body_bytes { true }
c.configure_rspec_metadata!
end
18 changes: 0 additions & 18 deletions test/helper.rb

This file was deleted.

0 comments on commit 3aa4f33

Please sign in to comment.