supermarket 0.0.2-universal-java → 0.0.3-universal-java

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.
data/CHANGES ADDED
@@ -0,0 +1,15 @@
1
+ 0.0.3 (10/08/20010)
2
+
3
+ * Added Sinatra based web API, deployable to GAE
4
+ * Categories
5
+
6
+ 0.0.2 (03/28/2010)
7
+ 0.0.1
8
+
9
+ * Different output formats (json, xml, html)
10
+ * Image output support
11
+ * Display all comments
12
+
13
+ 0.0.0 (03/23/2010)
14
+
15
+ * Initial Release
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem "json-jruby", :require=>'json'
4
+
5
+ group :development do
6
+ #gem "sinatra-reloader", :require=>"sinatra/reloader"
7
+ #gem "appengine-sdk"
8
+ end
9
+
10
+ group :web do
11
+ gem "sinatra", :require=>"sinatra/base"
12
+ gem "rack-respond_to", :require=>"rack/respond_to"
13
+ gem "rack-abstract-format", :require=>"rack/abstract_format"
14
+ end
15
+
data/README.md CHANGED
@@ -5,7 +5,7 @@ This is a thin JRuby wrapper for the [Android Market API](http://code.google.com
5
5
 
6
6
  It's a new project and only some parts of the protocol have been implemented. I decided to build on top of Java/JRuby because the native Ruby Protocolbuffer implementation ([ruby-protobuf](http://code.google.com/p/ruby-protobuf/)) could not properly handle the [.proto file](http://github.com/jberkel/android-market-api/blob/master/AndroidMarketApi/proto/market.proto) used by the API.
7
7
 
8
- ## Synopis
8
+ ## Synopsis
9
9
  require 'supermarket'
10
10
  session = Supermarket::Session.new
11
11
 
data/Rakefile ADDED
@@ -0,0 +1,167 @@
1
+ require 'rake/clean'
2
+ require 'date'
3
+ CLEAN.include('pkg', 'tmp')
4
+
5
+ #############################################################################
6
+ #
7
+ # Gem related stuff
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def platform
33
+ eval(IO.read(gemspec_file)).platform.to_s
34
+ end
35
+
36
+ def gem_file
37
+ "#{name}-#{version}-#{platform}.gem"
38
+ end
39
+
40
+ def replace_header(head, header_name)
41
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
42
+ end
43
+
44
+ #############################################################################
45
+ #
46
+ # Standard tasks
47
+ #
48
+ #############################################################################
49
+
50
+ task :default => :test
51
+
52
+ desc "Open an irb session preloaded with this library"
53
+ task :console do
54
+ sh "irb -rubygems -r ./lib/#{name}.rb"
55
+ end
56
+
57
+ #############################################################################
58
+ #
59
+ # Packaging tasks
60
+ #
61
+ #############################################################################
62
+
63
+ task :release => :build do
64
+ unless `git branch` =~ /^\* master$/
65
+ puts "You must be on the master branch to release!"
66
+ exit!
67
+ end
68
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
69
+ sh "git tag v#{version}"
70
+ sh "git push origin master --tags"
71
+ sh "gem push pkg/#{name}-#{version}.gem"
72
+ end
73
+
74
+ desc "Builds the gem"
75
+ task :build => :gemspec do
76
+ sh "mkdir -p pkg"
77
+ sh "gem build #{gemspec_file}"
78
+ sh "mv #{gem_file} pkg"
79
+ end
80
+
81
+ task :gemspec => :validate do
82
+ # read spec file and split out manifest section
83
+ spec = File.read(gemspec_file)
84
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
85
+
86
+ # replace name version and date
87
+ replace_header(head, :name)
88
+ replace_header(head, :version)
89
+ replace_header(head, :date)
90
+ #comment this out if your rubyforge_project has a different name
91
+ replace_header(head, :rubyforge_project)
92
+
93
+ # determine file list from git ls-files
94
+ files = `git ls-files`.
95
+ split("\n").
96
+ sort.
97
+ reject { |file| file =~ /^\./ }.
98
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
99
+ map { |file| " #{file}" }.
100
+ join("\n")
101
+
102
+ # piece file back together and write
103
+ manifest = " s.files = %w[\n#{files}\n ]\n"
104
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
105
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
106
+ puts "Updated #{gemspec_file}"
107
+ end
108
+
109
+ task :validate do
110
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
111
+ unless libfiles.empty?
112
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
113
+ exit!
114
+ end
115
+ unless Dir['VERSION*'].empty?
116
+ puts "A `VERSION` file at root level violates Gem best practices."
117
+ exit!
118
+ end
119
+ end
120
+
121
+ #############################################################################
122
+ #
123
+ # Appengine
124
+ #
125
+ #############################################################################
126
+
127
+ begin
128
+ require 'warber'
129
+
130
+ APPENGINE_WEB_XML = "appengine-web.xml"
131
+ war_dir = "tmp/war"
132
+ directory war_dir
133
+
134
+ warbler = Warbler::Task.new
135
+
136
+ task :explode => [:clean, :war, war_dir] do
137
+ sh "unzip #{warbler.config.war_name}.war -d #{war_dir}"
138
+ sh "mv #{war_dir}/WEB-INF/{.bundle,bundle}"
139
+ end
140
+
141
+ task :explode_gemjar => [:clean, 'war:gemjar', :war, war_dir] do
142
+ sh "unzip #{warbler.config.war_name}.war -d #{war_dir}"
143
+ end
144
+
145
+ desc "deploy to gae"
146
+ task :deploy => [:explode] do
147
+ begin
148
+ require '/opt/homebrew/Cellar/app-engine-java-sdk/1.3.2/lib/appengine-tools-api.jar'
149
+ Java::ComGoogleAppengineToolsAdmin::AppCfg.main(['update', war_dir].to_java(:string))
150
+ rescue LoadError
151
+ sh "appcfg.sh update #{war_dir}"
152
+ end
153
+ end
154
+
155
+ namespace :bundle do
156
+ task :install do
157
+ sh "jruby -S bundle install vendor/gems --disable-shared-gems"
158
+ end
159
+ end
160
+
161
+ def app_version
162
+ require 'rexml/document'
163
+ doc = REXML::Document.new(IO.read(APPENGINE_WEB_XML))
164
+ REXML::XPath.first(doc, 'appengine-web-app/version').text.to_i
165
+ end
166
+ rescue LoadError => e
167
+ end
data/appengine-web.xml ADDED
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
3
+ <application>supermarket-api</application>
4
+
5
+ <version>6</version>
6
+
7
+ <static-files/>
8
+
9
+ <resource-files>
10
+ </resource-files>
11
+
12
+ <sessions-enabled>false</sessions-enabled>
13
+
14
+ <system-properties>
15
+ <property name="jruby.management.enabled" value="false" />
16
+ <property name="os.arch" value=""/>
17
+ <property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
18
+ <property name="jruby.compile.fastest" value="true"/>
19
+ <property name="jruby.compile.frameless" value="true"/>
20
+ <property name="jruby.compile.positionless" value="true"/>
21
+ <property name="jruby.compile.threadless" value="false"/>
22
+ <property name="jruby.compile.fastops" value="false"/>
23
+ <property name="jruby.compile.fastcase" value="false"/>
24
+ <property name="jruby.compile.chainsize" value="500"/>
25
+ <property name="jruby.compile.lazyHandles" value="false"/>
26
+ <property name="jruby.compile.peephole" value="true"/>
27
+ <property name="jruby.debug.loadService" value="false"/>
28
+ </system-properties>
29
+ </appengine-web-app>
30
+
data/bin/market CHANGED
@@ -6,17 +6,22 @@ format = ARGV.map { |a| a[/--format=(\w+)/, 1]}.compact.first || "json"
6
6
  image = ARGV.map { |a| a[/--image-out=([^\s]+)/, 1]}.compact.first || "image.jpg"
7
7
 
8
8
  def usage
9
- puts "#{File.basename($0)} [search|comments|all_comments|image|imagedata] [query|app_id] [--format=json|xml|html] [--image-out=file]"
9
+ puts "#{File.basename($0)} [search|comments|all_comments|categories|image|imagedata|icondata] [query|app_id] [--format=json|xml|html] [--image-out=file]"
10
10
  exit 1
11
11
  end
12
12
 
13
13
  case command = ARGV.shift
14
+ when "categories"
15
+ puts Supermarket::Session.new.send(command).send("to_#{format.downcase}")
14
16
  when /\A(search|(all_)?comments|image)\Z/
15
17
  arg = ARGV.shift or usage
16
18
  puts Supermarket::Session.new.send(command, arg).send("to_#{format.downcase}")
17
19
  when 'imagedata'
18
20
  arg = ARGV.shift or usage
19
21
  File.open(image, 'w') { |f| f << Supermarket::Session.new.image_data(arg) }
22
+ when 'icondata'
23
+ arg = ARGV.shift or usage
24
+ File.open(image, 'w') { |f| f << Supermarket::Session.new.image_data(arg, :icon) }
20
25
  else usage
21
26
  end
22
27
 
data/config/warble.rb ADDED
@@ -0,0 +1,16 @@
1
+ require File.join('lib', 'supermarket')
2
+
3
+ Warbler::Config.new do |config|
4
+ config.dirs = %w(lib)
5
+ config.includes = FileList["appengine-web.xml", "config.ru"]
6
+ config.webxml.booter = :rack
7
+
8
+ config.webxml.jruby.min.runtimes = 1
9
+ config.webxml.jruby.max.runtimes = 1
10
+ config.webxml.jruby.init.serial = true
11
+
12
+ market_config = Supermarket::Session.config
13
+ config.webxml['market_login'] = market_config['login']
14
+ config.webxml['market_password'] = market_config['password']
15
+ end
16
+
data/config.ru ADDED
@@ -0,0 +1,13 @@
1
+ require File.expand_path('lib/supermarket/api.rb')
2
+ require 'rack/reloader'
3
+ #Sinatra::Application.set :environment, :production
4
+ use Rack::AbstractFormat
5
+ use Rack::Reloader, 0 if Sinatra::Application.development?
6
+
7
+ map '/login' do
8
+ run Supermarket::ClientLogin
9
+ end
10
+
11
+ map '/api' do
12
+ run Supermarket::Api
13
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ environment = ['.bundle', 'bundle'].map { |f|
4
+ File.expand_path("../../../#{f}/environment.rb", __FILE__)
5
+ }.select { |f| File.exists?(f) }
6
+
7
+ if environment.empty?
8
+ require 'rubygems'
9
+ require 'bundler'
10
+ Bundler.setup
11
+ else
12
+ require environment.first
13
+ end
14
+
15
+ require File.join(File.dirname(__FILE__), 'session')
16
+ Bundler.require(:default, :web)
17
+
18
+ module Supermarket
19
+ class Api < Sinatra::Base
20
+ include Rack::RespondTo
21
+ reset!
22
+
23
+ not_found do
24
+ content_type :json
25
+ [404, { 'error' => 'not found' }.to_json]
26
+ end
27
+
28
+ get("/:id/comments") do
29
+ session = Session.new
30
+ if comments = session.comments(params[:id])
31
+ respond_to do |wants|
32
+ wants.json {comments.to_json}
33
+ wants.xml {comments.to_xml}
34
+ wants.html {comments.to_html}
35
+ end
36
+ else
37
+ raise Sinatra::NotFound
38
+ end
39
+ end
40
+
41
+ # get("/:id/image") do
42
+ # content_type :jpeg
43
+ #
44
+ # session = Session.new
45
+ # session.image_data(params[:id])
46
+ # end
47
+
48
+ def respond_to
49
+ env['HTTP_ACCEPT'] ||= 'text/html'
50
+ Rack::RespondTo.env = env
51
+
52
+ super { |format|
53
+ yield(format).tap do |response|
54
+ type = Rack::RespondTo::Helpers.match(Rack::RespondTo.media_types, format).first
55
+ content_type(type) if type
56
+ end
57
+ }
58
+ end
59
+ end
60
+
61
+
62
+ class ClientLogin < Sinatra::Base
63
+ reset!
64
+ end
65
+ end
@@ -5,20 +5,17 @@ require File.dirname(__FILE__) + "/jars/protobuf-format-java-1.2-SNAPSHOT.jar"
5
5
  #http://code.google.com/p/protobuf-java-format/
6
6
  module Supermarket
7
7
  module Formats
8
- import 'com.google.protobuf.JsonFormat'
9
- import 'com.google.protobuf.XmlFormat'
10
- import 'com.google.protobuf.HtmlFormat'
11
8
 
12
9
  def to_json(*a)
13
- JsonFormat.printToString(self)
10
+ Java::ComGoogleProtobuf::JsonFormat.printToString(self)
14
11
  end
15
12
 
16
13
  def to_xml
17
- XmlFormat.printToString(self)
14
+ Java::ComGoogleProtobuf::XmlFormat.printToString(self)
18
15
  end
19
16
 
20
17
  def to_html
21
- HtmlFormat.printToString(self)
18
+ Java::ComGoogleProtobuf::HtmlFormat.printToString(self)
22
19
  end
23
20
 
24
21
  def to_ruby
@@ -19,22 +19,30 @@ module Supermarket
19
19
  class Session
20
20
  attr_reader :_session
21
21
 
22
- def initialize
22
+ def initialize(opts={})
23
+ opts.merge!(self.class.config)
23
24
  @_session = MarketSession.new
24
- @_session.login(config['login'], config['password'])
25
+ if opts['authToken']
26
+ @_session.setAuthToken(opts['authToken'])
27
+ else
28
+ raise "Need login and password" unless opts['login'] && opts['password']
29
+ @_session.login(opts['login'], opts['password'])
30
+ end
25
31
  end
26
32
 
27
- def config_file
33
+
34
+ def self.config_file
28
35
  File.join(ENV['HOME'], '.supermarket.yml')
29
36
  end
30
37
 
31
- def config
38
+ def self.config
32
39
  @config ||= begin
33
- unless File.exists?(config_file)
34
- File.open(config_file, 'w') { |f| f << YAML.dump('login'=>'someone@gmail.com', 'password'=>'secr3t') }
35
- raise "Android market config file not found. Please edit #{config_file}"
40
+ if defined? $servlet_context
41
+ { 'login' => $servlet_context.getInitParameter('market_login') ,
42
+ 'password' => $servlet_context.getInitParameter('market_password') }
43
+ else
44
+ File.exists?(config_file) ? YAML.load_file(config_file) : {}
36
45
  end
37
- YAML.load_file(config_file)
38
46
  end
39
47
  end
40
48
 
@@ -48,6 +56,10 @@ module Supermarket
48
56
  execute(request)
49
57
  end
50
58
 
59
+ def categories()
60
+ request = Market::CategoriesRequest.newBuilder().build()
61
+ execute(request)
62
+ end
51
63
 
52
64
  def comments(app_id, start=0, count=10)
53
65
  raise ArgumentError, "need app id" unless app_id
@@ -60,7 +72,8 @@ module Supermarket
60
72
  if resp = execute(request)
61
73
  resp
62
74
  else
63
- raise ArgumentError, "request returned nil"
75
+ #raise ArgumentError, "request returned nil"
76
+ nil
64
77
  end
65
78
  end
66
79
 
@@ -75,16 +88,23 @@ module Supermarket
75
88
  end
76
89
  end
77
90
 
78
- def image(app_id, usage=Market::GetImageRequest::AppImageUsage::SCREENSHOT, image_id='1')
91
+ def image(app_id, usage=:screenshot, image_id='1')
92
+ case usage
93
+ when :screenshot
94
+ usage_const = Market::GetImageRequest::AppImageUsage::SCREENSHOT
95
+ when :icon
96
+ usage_const = Market::GetImageRequest::AppImageUsage::ICON
97
+ end
98
+
79
99
  request = Market::GetImageRequest.newBuilder().
80
100
  setAppId(pkg_to_app_id(app_id)).
81
- setImageUsage(usage).
101
+ setImageUsage(usage_const).
82
102
  setImageId(image_id).build()
83
103
 
84
104
  execute(request)
85
105
  end
86
106
 
87
- def image_data(app_id, usage=Market::GetImageRequest::AppImageUsage::SCREENSHOT, image_id='1')
107
+ def image_data(app_id, usage=:screenshot, image_id='1')
88
108
  if resp = image(app_id, usage, image_id)
89
109
  String.from_java_bytes(resp.getImageData().toByteArray())
90
110
  else
data/lib/supermarket.rb CHANGED
@@ -1 +1,5 @@
1
+ module Supermarket
2
+ VERSION = '0.0.3'
3
+ end
4
+
1
5
  require File.join(File.dirname(__FILE__), 'supermarket', 'session')
@@ -0,0 +1,46 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'supermarket'
3
+ s.version = '0.0.3'
4
+ s.platform = 'universal-java'
5
+
6
+ s.rubyforge_project = 'supermarket'
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Jan Berkel"]
9
+ s.date = '2010-08-10'
10
+ s.default_executable = %q{market}
11
+ s.description = %q{An unoffical/reverse engineered API for Android market.}
12
+ s.email = %q{jan.berkel@gmail.com}
13
+ s.executables = ["market"]
14
+ s.extra_rdoc_files = [
15
+ "README.md"
16
+ ]
17
+
18
+ # = MANIFEST =
19
+ s.files = %w[
20
+ CHANGES
21
+ Gemfile
22
+ README.md
23
+ Rakefile
24
+ appengine-web.xml
25
+ bin/market
26
+ config.ru
27
+ config/warble.rb
28
+ lib/supermarket.rb
29
+ lib/supermarket/api.rb
30
+ lib/supermarket/formats.rb
31
+ lib/supermarket/jars/AndroidMarketApi.jar
32
+ lib/supermarket/jars/protobuf-format-java-1.2-SNAPSHOT.jar
33
+ lib/supermarket/jars/protobuf-java-2.2.0.jar
34
+ lib/supermarket/session.rb
35
+ supermarket.gemspec
36
+ ]
37
+ # = MANIFEST =
38
+ s.homepage = %q{http://github.com/jberkel/supermarket}
39
+ s.rdoc_options = ["--charset=UTF-8"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = %q{1.3.6}
42
+ s.summary = %q{JRuby bindings for android-market-api}
43
+
44
+ s.add_dependency(%q<json-jruby>, [">= 0"])
45
+ end
46
+
metadata CHANGED
@@ -3,75 +3,83 @@ name: supermarket
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
- - 0
7
- - 0
8
- - 2
9
- version: 0.0.2
6
+ - 0
7
+ - 0
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: universal-java
11
11
  authors:
12
- - Jan Berkel
12
+ - Jan Berkel
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-29 00:00:00 +02:00
17
+ date: 2010-08-10 00:00:00 +02:00
18
18
  default_executable: market
19
19
  dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: json-jruby
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- version: "0"
30
- type: :runtime
31
- version_requirements: *id001
20
+ - !ruby/object:Gem::Dependency
21
+ name: json-jruby
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
32
  description: An unoffical/reverse engineered API for Android market.
33
33
  email: jan.berkel@gmail.com
34
34
  executables:
35
- - market
35
+ - market
36
36
  extensions: []
37
37
 
38
38
  extra_rdoc_files:
39
- - README.md
39
+ - README.md
40
40
  files:
41
- - bin/market
42
- - lib/supermarket.rb
43
- - lib/supermarket/formats.rb
44
- - lib/supermarket/jars/AndroidMarketApi.jar
45
- - lib/supermarket/jars/protobuf-format-java-1.2-SNAPSHOT.jar
46
- - lib/supermarket/jars/protobuf-java-2.2.0.jar
47
- - lib/supermarket/session.rb
48
- - README.md
41
+ - CHANGES
42
+ - Gemfile
43
+ - README.md
44
+ - Rakefile
45
+ - appengine-web.xml
46
+ - bin/market
47
+ - config.ru
48
+ - config/warble.rb
49
+ - lib/supermarket.rb
50
+ - lib/supermarket/api.rb
51
+ - lib/supermarket/formats.rb
52
+ - lib/supermarket/jars/AndroidMarketApi.jar
53
+ - lib/supermarket/jars/protobuf-format-java-1.2-SNAPSHOT.jar
54
+ - lib/supermarket/jars/protobuf-java-2.2.0.jar
55
+ - lib/supermarket/session.rb
56
+ - supermarket.gemspec
49
57
  has_rdoc: true
50
58
  homepage: http://github.com/jberkel/supermarket
51
59
  licenses: []
52
60
 
53
61
  post_install_message:
54
62
  rdoc_options:
55
- - --charset=UTF-8
63
+ - --charset=UTF-8
56
64
  require_paths:
57
- - lib
65
+ - lib
58
66
  required_ruby_version: !ruby/object:Gem::Requirement
59
67
  requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- segments:
63
- - 0
64
- version: "0"
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
65
73
  required_rubygems_version: !ruby/object:Gem::Requirement
66
74
  requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- segments:
70
- - 0
71
- version: "0"
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
72
80
  requirements: []
73
81
 
74
- rubyforge_project:
82
+ rubyforge_project: supermarket
75
83
  rubygems_version: 1.3.6
76
84
  signing_key:
77
85
  specification_version: 3