app-store-emigrant 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,5 +1,10 @@
1
1
  CHANGELOG
2
2
 
3
+ v0.0.8
4
+ - Refactored CLI to use Thor
5
+ - Greatly improved usability for CLI
6
+ - Metadata cache may now be cleared
7
+
3
8
  v0.0.7
4
9
  - Loosened strictness on runtime dependencies
5
10
 
data/README.md CHANGED
@@ -14,14 +14,16 @@ For more information on the issues faced when moving countries with regards to A
14
14
 
15
15
  **TL;DR**: For reasons unknown to mankind, Apple has made it rather complicated to update applications bought in different stores, particularly after emigrating. iTunes mentions updates are available, but refuses to actually update these apps when asked to. These applications are also missing from the Purchases-tab.
16
16
 
17
- App Store Emigrant tries to soothe these pains - albeit only partially - by scanning your iTunes library folder for mobile applications and querying iTunes for the latest versions available. One can then manually go into the store and update each application, one by one. *sigh*
17
+ App Store Emigrant tries to soothe these pains - albeit only partially - by scanning your iTunes library folder for mobile applications and querying iTunes for the latest versions available. One can then manually go into the store and update each application, one by one.
18
18
 
19
- ![App Store Emigrant](http://office.moonsphere.net/app-store-emigrant.png)
19
+ ![App Store Emigrant](http://office.moonsphere.net/app-store-emigrant.png?v2)
20
20
 
21
21
  Installation
22
22
  ------------
23
23
 
24
- App Store Emigrant is available from RubyGems and can be installed through the command-line. Fire up your favourite terminal and run:
24
+ App Store Emigrant is available from RubyGems and can be installed through the command-line.
25
+
26
+ Fire up your favourite terminal and run:
25
27
 
26
28
  gem install app-store-emigrant
27
29
 
@@ -33,10 +35,16 @@ Installing on **OSX** and using the **default system Ruby**? Run:
33
35
  Usage
34
36
  -----
35
37
 
36
- Once installed, a new not-so-fantastically named binary called ```ase``` will be added to your path. Invoke the binary to start the verification process:
38
+ Once installed, a new not-so-fantastically named binary called ```ase``` will be added to your path.
39
+
40
+ Invoke its ```scan``` task to start the verification process:
41
+
42
+ ase scan
43
+
44
+ If problems arise finding your default library, specify where your mobile applications lurk:
37
45
 
38
- ase
46
+ ase scan ~/m00sic
39
47
 
40
- If App Store Emigrant complains that it cannot find your default library, help it along and specify where your mobile applications lurk:
48
+ To clear the cache of application metadata, run the scan task with the ```-c``` or ```--clear-cache``` flag.
41
49
 
42
- ase ~/m00sic
50
+ ase scan --clear-cache
@@ -12,20 +12,21 @@ Gem::Specification.new do |s|
12
12
  s.homepage = 'https://github.com/timkurvers/app-store-emigrant'
13
13
  s.summary = 'App Store Emigrant will manually attempt to verify whether any of your local mobile applications are out of date'
14
14
  s.description = 'App Store Emigrant will manually attempt to verify whether any of your local mobile applications are out of date, which iTunes - unfortunately - will refuse once you have moved countries'
15
-
15
+
16
16
  s.rubyforge_project = 'app-store-emigrant'
17
17
 
18
18
  s.files = `git ls-files`.split("\n")
19
19
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
21
  s.require_paths = ['lib']
22
-
22
+
23
23
  s.add_dependency 'rubyzip', '~> 0.9'
24
24
  s.add_dependency 'rainbow', '~> 1.1'
25
25
  s.add_dependency 'CFPropertyList', '~> 2.0'
26
-
26
+ s.add_dependency 'thor', '~> 0.16.0'
27
+
27
28
  s.add_development_dependency 'rake'
28
-
29
+
29
30
  if RUBY_VERSION < '1.9.2'
30
31
  s.add_dependency 'json'
31
32
  s.add_development_dependency 'minitest'
data/bin/ase CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  require 'app-store-emigrant'
4
4
 
5
- AppStore::Emigrant::CLI.new ARGV
5
+ AppStore::Emigrant::CLI.start
@@ -8,89 +8,101 @@ require 'zip/zipfilesystem'
8
8
  module AppStore; end
9
9
 
10
10
  module AppStore::Emigrant
11
-
11
+
12
12
  # Represents a single iTunes mobile application
13
13
  class App
14
-
14
+
15
15
  # List of valid extensions for an application
16
16
  VALID_EXTENSIONS = [
17
17
  '.ipa'
18
18
  ]
19
-
19
+
20
20
  # Regular expression to match a version number in filenames
21
21
  FILENAME_VERSION_REGEX = Regexp.new('([0-9.]+)(?:' + VALID_EXTENSIONS.join('|').gsub!('.', '\.') + ')')
22
-
22
+
23
23
  attr_reader :path
24
24
  attr_writer :clouddata
25
-
25
+
26
26
  # Initializes application from given path
27
27
  def initialize path
28
28
  @path = Pathname.new path
29
29
  @path = @path.expand_path unless @path.absolute?
30
-
30
+
31
31
  # Ensure application exists
32
32
  unless @path.file?
33
33
  raise DoesNotExist, "Given path is not a valid application: #{@path}"
34
34
  end
35
-
35
+
36
36
  # Ensure application has valid extension
37
37
  unless VALID_EXTENSIONS.include? @path.extname
38
38
  raise Invalid, "Given application does not have a valid extension: #{@path}"
39
39
  end
40
-
40
+
41
41
  @metadata = nil
42
42
  @clouddata = nil
43
43
  end
44
-
44
+
45
45
  # Filename of this application (including extension)
46
46
  def filename
47
47
  unless @filename
48
48
  @filename = @path.basename.to_s
49
49
  end
50
-
50
+
51
51
  @filename
52
52
  end
53
-
53
+
54
54
  # Unique application id
55
55
  def id
56
56
  metadata['itemId'] rescue nil
57
57
  end
58
-
58
+
59
59
  # Name of this application
60
60
  def name
61
61
  metadata['itemName'] rescue nil
62
62
  end
63
-
63
+
64
64
  # Whether this application is valid (validates metadata, id and name)
65
65
  def valid?
66
66
  metadata && id && name rescue false
67
67
  end
68
-
68
+
69
69
  # Version of this application
70
70
  def version
71
71
  unless @version
72
-
72
+
73
73
  # Extract version information (if available)
74
74
  @version = metadata['bundleShortVersionString'] || metadata['bundleVersion'] rescue nil
75
-
75
+
76
76
  # Otherwise, use the filename
77
77
  unless @version
78
78
  @version = filename[FILENAME_VERSION_REGEX, 1]
79
79
  end
80
-
80
+
81
81
  end
82
-
82
+
83
83
  @version
84
84
  end
85
-
85
+
86
+ # Property list name
87
+ def plist
88
+ Pathname.new(filename).basename('.ipa').to_s + '.plist'
89
+ end
90
+
91
+ # Whether this application's metadata is cached
92
+ def cached?
93
+ Cache.has? plist
94
+ end
95
+
96
+ # Forcefully caches this application's metadata
97
+ def cache!
98
+ metadata
99
+ end
100
+
86
101
  # Lazily loads local metadata for this application from its iTunesMetadata.plist
87
102
  def metadata
88
103
  unless @metadata
89
-
90
- # Determine plist name
91
- plist = Pathname.new(filename).basename('.ipa').to_s + '.plist'
92
-
93
- unless Cache.has?(plist)
104
+
105
+ unless cached?
94
106
  begin
95
107
  Zip::ZipFile.open(@path) do |zip|
96
108
  zip.extract('iTunesMetadata.plist', Cache.path_to(plist))
@@ -99,13 +111,13 @@ module AppStore::Emigrant
99
111
  raise Invalid, e.message
100
112
  end
101
113
  end
102
-
114
+
103
115
  @metadata = CFPropertyList.native_types(CFPropertyList::List.new(:file => Cache.path_to(plist)).value)
104
116
  end
105
-
117
+
106
118
  @metadata
107
119
  end
108
-
120
+
109
121
  # Lazily queries Apple's iTunes Store API for latest cloud data
110
122
  # Note: Clouddata may be nil if the application was removed from the store
111
123
  def clouddata
@@ -113,26 +125,26 @@ module AppStore::Emigrant
113
125
  response = Net::HTTP.get('itunes.apple.com', '/lookup?id=' + id.to_s)
114
126
  @clouddata = JSON.parse(response)['results'].first
115
127
  end
116
-
128
+
117
129
  @clouddata
118
130
  end
119
-
131
+
120
132
  # Version available in the cloud
121
133
  def cloudversion
122
134
  clouddata && clouddata['version']
123
135
  end
124
-
136
+
125
137
  # Whether this application is outdated
126
138
  def outdated?
127
139
  return cloudversion && version != cloudversion
128
140
  end
129
-
141
+
130
142
  # Raised when an application does not exist
131
143
  class DoesNotExist < StandardError; end
132
-
144
+
133
145
  # Raised when an application is invalid (e.g non-valid extension)
134
146
  class Invalid < StandardError; end
135
-
147
+
136
148
  end
137
-
149
+
138
150
  end
@@ -3,33 +3,40 @@ require 'pathname'
3
3
  module AppStore; end
4
4
 
5
5
  module AppStore::Emigrant
6
-
6
+
7
7
  # Cache mechanism
8
8
  class Cache
9
-
10
- PATH = begin
9
+
10
+ LOCATION = begin
11
11
  path = Pathname.new('~/.ase-cache').expand_path
12
12
  unless path.directory?
13
13
  path.mkpath
14
14
  end
15
15
  path
16
16
  end
17
-
17
+
18
18
  # Whether cache has this item
19
19
  def self.has? item
20
- PATH.join(item).file?
20
+ LOCATION.join(item).file?
21
21
  end
22
-
22
+
23
23
  # Path to given item (whether existent or not)
24
24
  def self.path_to item
25
- PATH.join(item).to_s
25
+ LOCATION.join(item).to_s
26
26
  end
27
-
27
+
28
28
  # Forcefully clears the cache
29
29
  def self.clear!
30
- # TODO: Implement clearing cache
30
+ LOCATION.children.each do |item|
31
+ item.delete if item.file?
32
+ end
33
+ end
34
+
35
+ # Number of items in the cache
36
+ def self.count
37
+ LOCATION.children.select { |item| item.file? }.length
31
38
  end
32
-
39
+
33
40
  end
34
-
41
+
35
42
  end
@@ -1,44 +1,89 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'rainbow'
4
+ require 'thor'
2
5
 
3
6
  module AppStore; end
4
7
 
5
8
  module AppStore::Emigrant
6
-
9
+
7
10
  # Represents the command line interface
8
- class CLI
9
-
10
- # Initializes CLI instance with given arguments
11
- def initialize args
12
-
13
- # Extract the path (if any)
14
- path, = args
15
-
11
+ class CLI < Thor
12
+
13
+ desc 'scan [LIBRARY PATH]', 'Scans an iTunes library and reports which of its mobile applications are out of date'
14
+ method_option :clear_cache, :type => :boolean, :default => false, :aliases => '-c', :desc => 'Clears application cache prior to scanning'
15
+ def scan path = nil
16
+
17
+ # Ensure all output is immediately flushed
18
+ $stdout.sync = true
19
+
16
20
  # Use the default library on this system when no path is specified
17
21
  library = path ? Library.new(path) : Library.default
18
-
19
- # Load cloud data in bulk
22
+
23
+ # Clear cache if requested
24
+ if options[:clear_cache]
25
+ Cache.clear!
26
+ end
27
+
28
+ # Verify cache integrity
29
+ puts 'Verifying cache integrity..'
30
+
31
+ # Forcefully cache metadata for each application that is not yet cached
32
+ library.apps.each do |app|
33
+
34
+ unless app.cached?
35
+ begin
36
+ app.cache!
37
+ puts " + #{app.name} v#{app.version}"
38
+ rescue App::Invalid => e
39
+ puts " ! Cannot cache #{app.filename}: #{e.message}".foreground(:red).bright
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ # Print cache statistics
46
+ puts "Done. Currently caching #{Cache.count} applications on your system."
47
+
48
+ puts
49
+
50
+ # Since all apps are cached, load cloud data in bulk
20
51
  library.clouddata!
21
-
52
+
53
+ # Print library statistics
54
+ puts "Your library contains #{library.valid_apps.length} valid applications, of which #{library.outdated_apps.length} are outdated:"
55
+
22
56
  # Loop through all applications
23
57
  library.apps.each do |app|
24
-
58
+
25
59
  if app.valid?
26
-
27
- # Print their name, version and whether it's outdated
28
- print app.name + ' @ ' + "v#{app.version}".foreground(app.outdated? ? :red : :green)
60
+
61
+ # Generate color-coded version
62
+ version = "v#{app.version}".foreground(app.outdated? ? :red : :green)
63
+ if app.outdated?
64
+ version = version.bright
65
+ end
66
+
67
+ # Print application name, version and whether it's outdated
68
+ print " · #{app.name} #{version}"
29
69
  if app.outdated?
30
- print " (v#{app.cloudversion} available in the cloud)"
70
+ print " · v#{app.cloudversion} available".foreground(:white)
31
71
  end
72
+
73
+ puts
32
74
  else
33
- print app.filename + ' is invalid (metadata, id or name missing)'
75
+ puts " ! #{app.filename} is invalid (metadata, id or name missing)".foreground(:red).bright
34
76
  end
35
-
36
- puts
37
-
77
+
38
78
  end
39
-
79
+
40
80
  end
41
-
81
+
82
+ desc 'version', 'Prints version information'
83
+ def version
84
+ puts "App Store Emigrant v#{AppStore::Emigrant::VERSION}"
85
+ end
86
+
42
87
  end
43
-
88
+
44
89
  end
@@ -5,34 +5,44 @@ require 'pathname'
5
5
  module AppStore; end
6
6
 
7
7
  module AppStore::Emigrant
8
-
8
+
9
9
  # Represents a single iTunes mobile applications library
10
10
  class Library
11
-
11
+
12
12
  attr_reader :path
13
-
13
+
14
14
  # Initializes library from given path
15
15
  def initialize path
16
16
  @path = Pathname.new path
17
17
  @path = @path.expand_path unless @path.absolute?
18
-
18
+
19
19
  # Ensure library is a valid directory
20
20
  unless @path.directory?
21
21
  raise DoesNotExist, "Given path is not a valid mobile applications library: #{@path}"
22
22
  end
23
-
23
+
24
24
  @apps = nil
25
25
  end
26
-
26
+
27
27
  # Retrieves a list of applications
28
28
  def apps
29
29
  unless @apps
30
30
  load!
31
31
  end
32
-
32
+
33
33
  @apps
34
34
  end
35
-
35
+
36
+ # Retrieves a list of valid applications
37
+ def valid_apps
38
+ apps.select { |app| app.valid? }
39
+ end
40
+
41
+ # Retrieves a list of outdated applications
42
+ def outdated_apps
43
+ apps.select { |app| app.valid? && app.outdated? }
44
+ end
45
+
36
46
  # Forcefully loads applications from disk
37
47
  def load!
38
48
  @apps = []
@@ -45,15 +55,15 @@ module AppStore::Emigrant
45
55
  end
46
56
  self
47
57
  end
48
-
58
+
49
59
  # Populates applications' cloud data in bulk
50
60
  def clouddata!
51
-
61
+
52
62
  # Collect all application ids, skipping any invalid ones
53
63
  ids = apps.collect do |app|
54
64
  app.id
55
65
  end.compact
56
-
66
+
57
67
  # Queries Apple's iTunes Store API for latest cloud data using undocumented bulk method
58
68
  response = Net::HTTP.get('itunes.apple.com', '/lookup?id=' + ids.join(','))
59
69
  results = JSON.parse(response)['results']
@@ -63,66 +73,66 @@ module AppStore::Emigrant
63
73
  end
64
74
  end
65
75
  end
66
-
76
+
67
77
  # Searches for application with given id
68
78
  def get id
69
79
  apps.select do |app|
70
80
  app.id == id
71
81
  end.first
72
82
  end
73
-
83
+
74
84
  # Searches for applications containing given snippet in filename
75
85
  def find snippet
76
86
  apps.select do |app|
77
87
  app.filename.include? snippet
78
88
  end
79
89
  end
80
-
90
+
81
91
  # Returns the default library (if any) for this system
82
92
  # See Apple's support documents as to where libraries can be found
83
93
  # - http://support.apple.com/kb/ht1391
84
94
  # - http://support.apple.com/kb/ht3847
85
95
  def self.default
86
-
96
+
87
97
  # Use the homedir provided through the environment
88
98
  homedir = ENV['HOME']
89
-
99
+
90
100
  # List all locations
91
101
  locations = [
92
-
102
+
93
103
  # Mac OSX and Windows Vista
94
104
  "#{homedir}/Music/iTunes/iTunes Media/Mobile Applications",
95
-
105
+
96
106
  # Windows 7
97
107
  "#{homedir}/My Music/iTunes/iTunes Media/Mobile Applications",
98
-
108
+
99
109
  # Windows XP
100
110
  "#{homedir}/My Documents/My Music/iTunes/iTunes Media/Mobile Applications",
101
-
111
+
102
112
  # Mac OSX and Windows Vista (prior to iTunes 9)
103
113
  "#{homedir}/Music/iTunes/Mobile Applications",
104
-
114
+
105
115
  # Windows 7 (prior to iTunes 9)
106
116
  "#{homedir}/My Music/iTunes/Mobile Applications",
107
-
117
+
108
118
  # Windows XP (prior to iTunes 9)
109
119
  "#{homedir}/My Documents/My Music/iTunes/Mobile Applications",
110
-
120
+
111
121
  ]
112
-
122
+
113
123
  # Raise exception if no default library could be found
114
124
  path = Dir.glob(locations).first
115
125
  unless path
116
126
  raise DoesNotExist, 'Could not locate default iTunes mobile applications library'
117
127
  end
118
-
128
+
119
129
  # Return an instance of this default library
120
130
  Library.new path
121
131
  end
122
-
132
+
123
133
  # Raised when a library does not exist
124
134
  class DoesNotExist < StandardError; end
125
-
135
+
126
136
  end
127
-
137
+
128
138
  end
@@ -2,7 +2,7 @@
2
2
  module AppStore; end
3
3
 
4
4
  module AppStore::Emigrant
5
-
6
- VERSION = '0.0.7'
5
+
6
+ VERSION = '0.0.8'
7
7
 
8
8
  end
data/specs/app.rb CHANGED
@@ -6,56 +6,56 @@ require 'minitest/autorun'
6
6
  include AppStore::Emigrant
7
7
 
8
8
  describe App do
9
-
9
+
10
10
  LIBRARY = ROOT + '/fixtures/dummy-library'
11
-
11
+
12
12
  before do
13
13
  @dummy = App.new(LIBRARY + '/Dummy.ipa')
14
14
  @gta = App.new(LIBRARY + '/GTA.ipa')
15
15
  @soosiz = App.new(LIBRARY + '/Soosiz.ipa')
16
16
  end
17
-
17
+
18
18
  it 'must be a valid file on disk' do
19
19
  lambda do
20
20
  App.new(LIBRARY + '/Non-Existent.ipa')
21
21
  end.must_raise App::DoesNotExist
22
22
  end
23
-
23
+
24
24
  it 'must have a valid extension' do
25
25
  lambda do
26
26
  App.new(LIBRARY + '/Non-Existent.ipa')
27
27
  end.must_raise App::DoesNotExist
28
28
  end
29
-
29
+
30
30
  it 'can determine its own filename' do
31
31
  @gta.filename.must_equal 'GTA.ipa'
32
32
  @soosiz.filename.must_equal 'Soosiz.ipa'
33
33
  end
34
-
34
+
35
35
  it 'will report invalid structures' do
36
36
  @dummy.valid?.must_equal false
37
37
  @dummy.id.must_equal nil
38
38
  @dummy.version.must_equal nil
39
39
  end
40
-
40
+
41
41
  it 'can extract its name' do
42
42
  @gta.name.must_equal 'Grand Theft Auto: Chinatown Wars'
43
43
  @soosiz.name.must_equal 'Soosiz'
44
44
  end
45
-
45
+
46
46
  it 'can query local metadata' do
47
47
  @gta.version.must_equal '0.9'
48
48
  @soosiz.version.must_equal '1.1'
49
49
  end
50
-
50
+
51
51
  it 'can load cloud data' do
52
52
  @gta.cloudversion.must_equal '1.1.0'
53
53
  @soosiz.cloudversion.must_equal '1.3'
54
54
  end
55
-
55
+
56
56
  it 'can determine whether it is outdated' do
57
57
  @gta.outdated?.must_equal true
58
58
  @soosiz.outdated?.must_equal true
59
59
  end
60
-
60
+
61
61
  end
data/specs/library.rb CHANGED
@@ -6,46 +6,48 @@ require 'minitest/autorun'
6
6
  include AppStore::Emigrant
7
7
 
8
8
  describe Library do
9
-
9
+
10
10
  before do
11
11
  @library = Library.new(ROOT + '/fixtures/dummy-library')
12
12
  end
13
-
13
+
14
14
  it 'must be located in a valid directory' do
15
15
  @library.must_be_instance_of Library
16
-
16
+
17
17
  lambda do
18
18
  Library.new(ROOT + '/non-existent-library')
19
19
  end.must_raise Library::DoesNotExist
20
20
  end
21
-
21
+
22
22
  it 'will gracefully and lazily load applications' do
23
23
  @library.instance_variable_get('@apps').must_be_nil
24
24
  @library.apps.must_be_instance_of Array
25
25
  @library.apps.length.must_equal 3
26
+ @library.valid_apps.must_be_instance_of Array
27
+ @library.valid_apps.length.must_equal 2
26
28
  end
27
-
29
+
28
30
  it 'can find applications by (partial) filename' do
29
31
  @library.find('Dummy').length.must_equal 1
30
32
  @library.find('GTA').length.must_equal 1
31
33
  @library.find('Soosiz').length.must_equal 1
32
34
  end
33
-
35
+
34
36
  it 'can get applications by id' do
35
37
  @library.get(344186162).filename.must_equal 'GTA.ipa'
36
38
  @library.get(331891505).filename.must_equal 'Soosiz.ipa'
37
39
  end
38
-
40
+
39
41
  it 'can load cloud data in bulk' do
40
42
  gta = @library.find('GTA').first
41
43
  soosiz = @library.find('Soosiz').first
42
44
  gta.instance_variable_get('@clouddata').must_be_nil
43
45
  soosiz.instance_variable_get('@clouddata').must_be_nil
44
-
46
+
45
47
  @library.clouddata!
46
-
48
+
47
49
  gta.instance_variable_get('@clouddata').must_be_instance_of Hash
48
50
  soosiz.instance_variable_get('@clouddata').must_be_instance_of Hash
49
51
  end
50
-
52
+
51
53
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app-store-emigrant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-31 00:00:00.000000000 Z
12
+ date: 2012-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rubyzip
16
- requirement: &70275229291660 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '0.9'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70275229291660
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.9'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rainbow
27
- requirement: &70275229291160 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '1.1'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *70275229291160
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.1'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: CFPropertyList
38
- requirement: &70275229290700 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ~>
@@ -43,10 +53,31 @@ dependencies:
43
53
  version: '2.0'
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *70275229290700
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: thor
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.16.0
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.16.0
47
78
  - !ruby/object:Gem::Dependency
48
79
  name: rake
49
- requirement: &70275229290320 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
50
81
  none: false
51
82
  requirements:
52
83
  - - ! '>='
@@ -54,7 +85,12 @@ dependencies:
54
85
  version: '0'
55
86
  type: :development
56
87
  prerelease: false
57
- version_requirements: *70275229290320
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
58
94
  description: App Store Emigrant will manually attempt to verify whether any of your
59
95
  local mobile applications are out of date, which iTunes - unfortunately - will refuse
60
96
  once you have moved countries
@@ -101,21 +137,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
137
  - - ! '>='
102
138
  - !ruby/object:Gem::Version
103
139
  version: '0'
104
- segments:
105
- - 0
106
- hash: -972531457948704449
107
140
  required_rubygems_version: !ruby/object:Gem::Requirement
108
141
  none: false
109
142
  requirements:
110
143
  - - ! '>='
111
144
  - !ruby/object:Gem::Version
112
145
  version: '0'
113
- segments:
114
- - 0
115
- hash: -972531457948704449
116
146
  requirements: []
117
147
  rubyforge_project: app-store-emigrant
118
- rubygems_version: 1.8.17
148
+ rubygems_version: 1.8.24
119
149
  signing_key:
120
150
  specification_version: 3
121
151
  summary: App Store Emigrant will manually attempt to verify whether any of your local