ruby-aaws-simple 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ #gem 'ruby-aaws', '0.8.1'
4
+ gem 'ruby-aaws'
5
+
6
+ # Specify your gem's dependencies in ruby-aaws-simple.gemspec
7
+ gemspec
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # ruby-aaws-simple
2
+ Simple wrapper for ruby-aaws
3
+
4
+ ## Installation
5
+ gem install ruby-aaws-simple
6
+
7
+ ## Usage
8
+ require 'amazon/aws/simple'
9
+ aws = Amazon::AWS::Simple::Search.new(key_id, secret_key_id, affiliate_tag, country_code, encoding, cacahe_dir)
10
+ items = aws.retrieve_by_keyword('Ruby')
11
+ items.first.title
12
+ # => 7.50 Carat Ruby & White Sapphire Heart Pendant in Sterling Silver with 18" Chain,
13
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/examples/test.rb ADDED
@@ -0,0 +1,12 @@
1
+ #!/bin/env ruby
2
+ require 'amazon/aws/simple'
3
+
4
+ if $0 == __FILE__
5
+ key_id = ""
6
+ secret_key_id = ""
7
+ cache_dir = "/tmp/amazon/"
8
+
9
+ Amazon::AWS::Simple::Search.logger = Logger.new(STDERR)
10
+ aws = Amazon::AWS::Simple::Search.new(key_id, secret_key_id, "hoge-22", "us", "utf-8", cache_dir)
11
+ puts aws.retrieve_by_keyword('ruby').map(&:title)
12
+ end
@@ -0,0 +1,143 @@
1
+ # monkey patch
2
+ #
3
+ module Amazon
4
+
5
+ module AWS
6
+
7
+ # This class provides a simple results caching system for operations
8
+ # performed by AWS.
9
+ #
10
+ # To use it, set _cache_ to *true* in either <tt>/etc/amazonrc</tt> or
11
+ # <tt>~/.amazonrc</tt>.
12
+ #
13
+ # By default, the cache directory used is <tt>/tmp/amazon</tt>, but this
14
+ # can be changed by defining _cache_dir_ in either <tt>/etc/amazonrc</tt>
15
+ # or <tt>~/.amazonrc</tt>.
16
+ #
17
+ # When a cache is used, Ruby/AWS will check the cache directory for a
18
+ # recent copy of a response to the exact operation that you are
19
+ # performing. If found, the cached response will be returned instead of
20
+ # the request being forwarded to the AWS servers for processing. If no
21
+ # (recent) copy is found, the request will be forwarded to the AWS servers
22
+ # as usual. Recency is defined here as less than 24 hours old.
23
+ #
24
+ class Cache
25
+
26
+ require 'fileutils'
27
+
28
+ begin
29
+ require 'md5'
30
+ rescue LoadError
31
+ # Ruby 1.9 has moved MD5.
32
+ #
33
+ require 'digest/md5'
34
+ end
35
+
36
+ # Exception class for bad cache paths.
37
+ #
38
+ class PathError < StandardError; end
39
+
40
+ # Length of one day in seconds
41
+ #
42
+ ONE_DAY = 86400 # :nodoc:
43
+
44
+ # Age in days below which to consider cache files valid.
45
+ #
46
+ MAX_AGE = 1.0
47
+
48
+ # Default cache location.
49
+ #
50
+ DEFAULT_CACHE_DIR = '/tmp/amazon'
51
+
52
+ attr_reader :path
53
+
54
+ def initialize(path=DEFAULT_CACHE_DIR)
55
+ path ||= DEFAULT_CACHE_DIR
56
+
57
+ ::FileUtils::mkdir_p( path ) unless File.exists? path
58
+
59
+ unless File.directory? path
60
+ raise PathError, "cache path #{path} is not a directory"
61
+ end
62
+
63
+ unless File.readable? path
64
+ raise PathError, "cache path #{path} is not readable"
65
+ end
66
+
67
+ unless File.writable? path
68
+ raise PathError, "cache path #{path} is not writable"
69
+ end
70
+
71
+ @path = path
72
+ end
73
+
74
+
75
+ # Determine whether or not the the response to a given URL is cached.
76
+ # Returns *true* or *false*.
77
+ #
78
+ def cached?(url)
79
+ digest = Digest::MD5.hexdigest( url )
80
+
81
+ cache_files = Dir.glob( File.join( @path, '*' ) ).map do |d|
82
+ File.basename( d )
83
+ end
84
+
85
+ return cache_files.include?( digest ) &&
86
+ ( Time.now - File.mtime( File.join( @path, digest ) ) ) /
87
+ ONE_DAY <= MAX_AGE
88
+ end
89
+
90
+
91
+ # Retrieve the cached response associated with _url_.
92
+ #
93
+ def fetch(url)
94
+ digest = Digest::MD5.hexdigest( url )
95
+ cache_file = File.join( @path, digest )
96
+
97
+ return nil unless File.exist? cache_file
98
+
99
+ Amazon.dprintf( 'Fetching %s from cache...', digest )
100
+ #File.open( File.join( cache_file ) ).readlines.to_s
101
+ File.read(cache_file)
102
+ end
103
+
104
+
105
+ # Cache the data from _contents_ and associate it with _url_.
106
+ #
107
+ def store(url, contents)
108
+ digest = Digest::MD5.hexdigest( url )
109
+ cache_file = File.join( @path, digest )
110
+
111
+ Amazon.dprintf( 'Caching %s...', digest )
112
+ content.force_encoding("UTF-8")
113
+ #File.open( cache_file, 'w' ) { |f| f.puts contents }
114
+ File.write cache_file, contents
115
+ end
116
+
117
+
118
+ # This method flushes all files from the cache directory specified
119
+ # in the object's <i>@path</i> variable.
120
+ #
121
+ def flush_all
122
+ FileUtils.rm Dir.glob( File.join( @path, '*' ) )
123
+ end
124
+
125
+
126
+ # This method flushes expired files from the cache directory specified
127
+ # in the object's <i>@path</i> variable.
128
+ #
129
+ def flush_expired
130
+ now = Time.now
131
+
132
+ expired_files = Dir.glob( File.join( @path, '*' ) ).find_all do |f|
133
+ ( now - File.mtime( f ) ) / ONE_DAY > MAX_AGE
134
+ end
135
+
136
+ FileUtils.rm expired_files
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,183 @@
1
+ require_relative "simple_version"
2
+ require 'amazon/aws/search'
3
+ require 'amazon/aws'
4
+ require 'logger'
5
+ require 'cgi'
6
+
7
+ module Amazon::AWS::Simple
8
+ class APIWrapper
9
+ @@logger = Logger.new(nil)
10
+ def self.logger=(logger)
11
+ @@logger = logger
12
+ end
13
+
14
+ def initialize(key_id, secret_key_id, tag, locale, encoding, cache_dir)
15
+ @key_id = key_id
16
+ @secret_key_id = secret_key_id
17
+ @tag = tag
18
+ @locale = locale
19
+ @encoding = encoding
20
+ @cache_dir = cache_dir
21
+ end
22
+
23
+ def request(query)
24
+ req = Amazon::AWS::Search::Request.new(@key_id, @tag)
25
+ req.config["cache_dir"] = @cache_dir
26
+ req.config["secret_key_id"] = @secret_key_id
27
+ req.locale = @locale
28
+ req.encoding = @encoding
29
+ req.cache = Amazon::AWS::Cache.new(@cache_dir)
30
+
31
+ rg = Amazon::AWS::ResponseGroup.new(:Large)
32
+ query.response_group = rg
33
+
34
+ req.search(query)
35
+ end
36
+
37
+ def item_lookup(type, params={})
38
+ request(Amazon::AWS::ItemLookup.new(type, params)).item_lookup_response.items.item
39
+ end
40
+
41
+ def item_search(type, params={})
42
+ request(Amazon::AWS::ItemSearch.new(type, params)).item_search_response.items.item
43
+ end
44
+ end
45
+
46
+ class Search < APIWrapper
47
+ attr_reader :errors
48
+ def initialize(*args)
49
+ super(*args)
50
+ @errors = []
51
+ end
52
+
53
+ ## どんだけたくさんのASINでも全部自動でAPIの最大数にあわせて分割してリクエストしてくれる版
54
+ ## エラーは全部無視しますが、@errorsに記録されます
55
+ ITEM_LOOKUP_MAX_ITEMS = 10
56
+ def search_by_asin(*asins)
57
+ asins.flatten.each_slice(ITEM_LOOKUP_MAX_ITEMS).map{ |asin_codes|
58
+ @@logger.info "try to fetch: #{asin_codes.inspect}"
59
+ _search_by_asin(asin_codes)
60
+ }.flatten
61
+ end
62
+
63
+ def search_by_keyword(keyword)
64
+ _search_by_keyword(keyword)
65
+ end
66
+
67
+ ## 更につかいやすくしたやつ
68
+ def retrieve_by_asin(*asins)
69
+ search_by_asin(*asins).map{ |item|
70
+ Data.new.load_from_aws_item(item)
71
+ }
72
+ end
73
+
74
+ def retrieve_by_keyword(keyword)
75
+ search_by_keyword(keyword).map{ |item|
76
+ Data.new.load_from_aws_item(item)
77
+ }
78
+ end
79
+
80
+ private
81
+ # 10以上は検索できないAPI, 仕様を満たしてる
82
+ def _search_by_asin(*asins)
83
+ params = asins.flatten
84
+ if params.size > ITEM_LOOKUP_MAX_ITEMS
85
+ raise ArgumentError.new("asin_codes > #{ITEM_LOOKUP_MAX_ITEMS}, #{params.inspect}")
86
+ end
87
+ begin
88
+ results = item_lookup("ASIN", {"ItemId" => params.join(",")})
89
+ rescue Amazon::AmazonError => ex
90
+ @@logger.error "Multiple fetch mode error! change to single fetch mode: #{ex}"
91
+ @@logger.error ex.backtrace.join($/)
92
+ results = []
93
+ params.each{ |asin|
94
+ begin
95
+ @@logger.info "try to fetch: #{asin.inspect}"
96
+ results << item_lookup("ASIN", {"ItemId" => asin})
97
+ rescue Amazon::AmazonError => ex
98
+ @@logger.error ex
99
+ @@logger.error ex.backtrace.join($/)
100
+ @errors << asin
101
+ end
102
+ }
103
+ results
104
+ end
105
+ end
106
+
107
+ def _search_by_keyword(keyword)
108
+ item_search("All", {'Keywords' => keyword})
109
+ end
110
+ end
111
+
112
+ class Search::Data
113
+ attr_accessor :asin
114
+ attr_accessor :title
115
+ attr_accessor :product_group
116
+ attr_accessor :publisher
117
+ attr_accessor :published_at
118
+ attr_accessor :image_url
119
+ attr_accessor :image_code
120
+ attr_accessor :alt_image_urls
121
+ attr_accessor :alt_image_codes
122
+ attr_accessor :price
123
+ attr_accessor :discount_price
124
+ attr_accessor :discount_percentage
125
+ attr_accessor :detail
126
+
127
+ def load_from_aws_item(item)
128
+ # 値段関係
129
+ price = item.item_attributes.list_price.amount.first rescue nil
130
+ discount_price = item.offers.offer.offer_listing.price.amount.first rescue nil
131
+ discount_percentage = item.offers.offer.offer_listing.percentage_saved.first rescue nil
132
+
133
+ # 画像関係
134
+ image_url = item.large_image.url rescue nil
135
+ image_code = extract_image_code_from_image_url(image_url)
136
+ alt_image_urls = item.image_sets.image_set.map{ |set| set.swatch_image.url }.flatten rescue []
137
+ alt_image_codes = alt_image_urls.map{|url| extract_image_code_from_image_url(url) }
138
+
139
+ # 日付関係
140
+ publication_date = item.item_attributes.publication_date.first rescue nil
141
+ release_date = item.item_attributes.release_date.first rescue nil
142
+
143
+ published_at = publication_date
144
+ if published_at.nil?
145
+ published_at = release_date
146
+ end
147
+
148
+ @asin = item.asin.first.to_s rescue nil
149
+ @title = CGI.unescape_html(item.item_attributes.title.join(",")) rescue nil
150
+ @product_group = item.item_attributes.product_group.first.to_s
151
+ @publisher = item.item_attributes.publisher.join(",") rescue nil
152
+ @published_at = published_at rescue nil
153
+ @image_url = image_url.first.to_s rescue nil
154
+ @image_code = image_code
155
+ @alt_image_urls = alt_image_urls
156
+ @alt_image_codes = alt_image_codes
157
+ @price = price
158
+ @discount_price = discount_price
159
+ @discount_percentage = discount_percentage
160
+ @detail = item.detail_page_url rescue nil
161
+ self
162
+ end
163
+
164
+ def to_s
165
+ "#<AWS::Simple::Data: #{@title}(#{@asin}) - #{@publisher} $#{@price}>"
166
+ end
167
+
168
+ private
169
+ def extract_basename_from_image_url(image_url)
170
+ if /([^\/]+)\.jpg$/.match(image_url)
171
+ Regexp.last_match(0)
172
+ end
173
+ end
174
+
175
+ def extract_image_code_from_image_url(image_url)
176
+ basename = extract_basename_from_image_url(image_url)
177
+ # 先頭の.までを抽出
178
+ if /(^[^\.]+)\./.match(basename)
179
+ Regexp.last_match(1)
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,7 @@
1
+ module Amazon
2
+ module AWS
3
+ module Simple
4
+ VERSION = "0.0.2"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/amazon/aws/simple_version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["kimoto"]
6
+ gem.email = ["sub+peerler@gmail.com"]
7
+ gem.description = %q{Simple Wrapper for ruby-aaws}
8
+ gem.summary = %q{Simple Wrapper for ruby-aaws}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "ruby-aaws-simple"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Amazon::AWS::Simple::VERSION
17
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-aaws-simple
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - kimoto
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-24 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Simple Wrapper for ruby-aaws
15
+ email:
16
+ - sub+peerler@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - README.md
24
+ - Rakefile
25
+ - examples/test.rb
26
+ - lib/amazon/aws/cache.rb
27
+ - lib/amazon/aws/simple.rb
28
+ - lib/amazon/aws/simple_version.rb
29
+ - ruby-aaws-simple.gemspec
30
+ homepage: ''
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 1.8.24
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: Simple Wrapper for ruby-aaws
54
+ test_files: []