power_reviews 0.1.1 → 0.3.2
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 +7 -0
- data/README +67 -7
- data/Rakefile +4 -2
- data/VERSION +1 -1
- data/generators/power_reviews/templates/config/power_reviews.yml +6 -4
- data/generators/power_reviews/templates/lib/tasks/power_reviews_tasks.rake +4 -10
- data/lib/power_reviews/config.rb +22 -11
- data/lib/power_reviews/feed.rb +3 -2
- data/lib/power_reviews/protocols/base.rb +3 -0
- data/lib/power_reviews/protocols/cp.rb +4 -0
- data/lib/power_reviews/protocols/ftp.rb +5 -0
- data/lib/power_reviews/review_data.rb +100 -0
- data/lib/power_reviews/sync.rb +34 -18
- data/lib/power_reviews/view_helpers.rb +88 -13
- data/lib/power_reviews.rb +1 -0
- data/power_reviews.gemspec +55 -46
- data/test/fixtures/rawdata/review_data_complete.xml +81 -0
- data/test/fixtures/rawdata/review_data_complete.xsd +344 -0
- data/test/fixtures/rawdata/review_data_summary.xml +1967 -0
- data/test/fixtures/rawdata/review_data_summary.xsd +161 -0
- data/test/power_reviews/config_test.rb +21 -0
- data/test/power_reviews/review_data_test.rb +41 -0
- data/test/power_reviews/view_helpers_test.rb +26 -0
- data/test/power_reviews_test.rb +0 -1
- metadata +85 -53
- data/.gitignore +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b2a2e183b2e2a588ad0b7f13a74d761b3d4f5583
|
4
|
+
data.tar.gz: dd366a763d0c19fe4bd17e5eaeeb1aef0b0d3789
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6bbbedf27521de7be69d7bb136477ea5535a4d38c2c848eab439ee84dd2f083b256838c3a517223325e07ef328af649802783daec374b0f08d2a6a4eb9515c23
|
7
|
+
data.tar.gz: de26c90d3c0cdcc72d339421a71df29a2ea8b7ed8332dfea6656ce45231a1dd6d00d655ff76def731678ff04a6e56e65234230dd657360a1a94f30f5c29534ae
|
data/README
CHANGED
@@ -1,13 +1,73 @@
|
|
1
|
-
PowerReviews
|
2
|
-
============
|
1
|
+
= PowerReviews
|
3
2
|
|
4
|
-
|
3
|
+
Integrates the third party PowerReviews service with Ruby. Currently focused on Ruby on Rails
|
4
|
+
but includes some tools to aid in non-rails tasks like data feed generation and automated
|
5
|
+
zip downloads/uploads.
|
5
6
|
|
7
|
+
== Dependencies
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
PowerReviews gem requires FasterCSV[http://fastercsv.rubyforge.org/] for csv generation and
|
10
|
+
Whenever[http://www.github.com/javan/whenever] for managing your crontab. It also requires that
|
11
|
+
a native +zip+ tool be installed.
|
9
12
|
|
10
|
-
|
13
|
+
which zip
|
14
|
+
# /usr/bin/zip
|
11
15
|
|
16
|
+
== Getting Started
|
12
17
|
|
13
|
-
|
18
|
+
Step one, install the gem.
|
19
|
+
|
20
|
+
In your rails environment file:
|
21
|
+
|
22
|
+
config.gem 'power_reviews', :source => 'http://gems.k2sportsdev.com'
|
23
|
+
|
24
|
+
Then
|
25
|
+
|
26
|
+
rake gems:install
|
27
|
+
|
28
|
+
or from your shell:
|
29
|
+
|
30
|
+
gem install power_reviews --source=http://gems.k2sportsdev.com
|
31
|
+
|
32
|
+
With the gem installed it's now time to generate the necessary files in your rails project.
|
33
|
+
From the root of your rails project run:
|
34
|
+
|
35
|
+
script/generate power_reviews
|
36
|
+
|
37
|
+
Which will output:
|
38
|
+
|
39
|
+
exists lib/tasks
|
40
|
+
create lib/tasks/power_reviews_tasks.rake
|
41
|
+
exists config/initializers
|
42
|
+
create config/power_reviews.yml
|
43
|
+
create config/initializers/power_reviews.rb
|
44
|
+
create config/schedule.rb
|
45
|
+
|
46
|
+
=== Power Reviews configuration
|
47
|
+
|
48
|
+
Define which files the PowerReviews::Sync class will be looking for when doing its nigtly download
|
49
|
+
of files, like the database.yml file in your rails configuration you can have a different configuration
|
50
|
+
for each environment. In this example, for development PowerReviews will use the local filesystem instead
|
51
|
+
of connection to the ftp server with the live data.
|
52
|
+
|
53
|
+
[+:protocol+] is the type of sync client you wish to use +:cp+ or +:ftp+
|
54
|
+
[+:zip+l] the zip file you will receive from Power Reviews
|
55
|
+
|
56
|
+
development:
|
57
|
+
protocol: cp
|
58
|
+
zip: test/brand.zip
|
59
|
+
done: test/brand_done.txt
|
60
|
+
datafeed: tmp/brand_feed.zip
|
61
|
+
|
62
|
+
production:
|
63
|
+
protocol: ftp
|
64
|
+
zip: brand.zip
|
65
|
+
done: brand_done.txt
|
66
|
+
data_feed: brand_data.zip
|
67
|
+
host: partners.powerreviews.com
|
68
|
+
username: user
|
69
|
+
password: passy
|
70
|
+
|
71
|
+
== Example
|
72
|
+
|
73
|
+
Copyright (c) 2009 K2 Sports, released under the MIT license
|
data/Rakefile
CHANGED
@@ -12,11 +12,13 @@ begin
|
|
12
12
|
gemspec.email = "beaucollins@gmail.com"
|
13
13
|
gemspec.homepage = "http://github.com/beaucollins/power_reviews"
|
14
14
|
gemspec.authors = ["Beau Collins"]
|
15
|
-
gemspec.add_runtime_dependency '
|
15
|
+
gemspec.add_runtime_dependency 'whenever'
|
16
16
|
gemspec.add_runtime_dependency 'fastercsv'
|
17
|
+
gemspec.add_development_dependency 'activesupport'
|
18
|
+
gemspec.add_development_dependency 'shoulda'
|
17
19
|
end
|
18
20
|
rescue LoadError
|
19
|
-
puts "Jeweler not available. Install it with:
|
21
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
20
22
|
end
|
21
23
|
|
22
24
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.2
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# For retrieving the zip file from PowerReviews
|
1
|
+
# For retrieving the zip file from PowerReviews and delivering your updated data feed
|
2
2
|
#
|
3
3
|
#
|
4
4
|
|
@@ -6,11 +6,13 @@ development:
|
|
6
6
|
protocol: cp
|
7
7
|
zip: test/k2skis.zip
|
8
8
|
done: test/k2skis_done.txt
|
9
|
+
datafeed: test/k2skis_data.zip
|
9
10
|
|
10
11
|
production:
|
11
12
|
protocol: ftp
|
12
13
|
zip: k2skis.zip
|
13
14
|
done: k2skis_done.txt
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
data_feed: k2skis_data.zip
|
16
|
+
host: partners.powerreviews.com
|
17
|
+
username: user
|
18
|
+
password: passy
|
@@ -1,19 +1,13 @@
|
|
1
|
-
# desc "Explaining what the task does"
|
2
|
-
# task :power_reviews do
|
3
|
-
# # Task goes here
|
4
|
-
# end
|
5
1
|
namespace :power_reviews do
|
6
2
|
|
7
|
-
desc "
|
3
|
+
desc "Outputs the PowerReviews feed in CSV format"
|
8
4
|
task :feed => :environment do
|
9
|
-
puts
|
10
|
-
PowerReviews::Feed.process
|
11
|
-
puts "Completed"
|
5
|
+
puts PowerReviews::Feed.process
|
12
6
|
end
|
13
7
|
|
14
|
-
desc "Copy the zip file from the ftp and unpack it"
|
8
|
+
desc "Copy the zip file from the ftp and unpack it then deliver the product feed"
|
15
9
|
task :sync => :environment do
|
16
|
-
puts "
|
10
|
+
puts "Syncing PowerReviews data"
|
17
11
|
PowerReviews::Sync.execute
|
18
12
|
puts "Completed"
|
19
13
|
end
|
data/lib/power_reviews/config.rb
CHANGED
@@ -1,20 +1,31 @@
|
|
1
1
|
module PowerReviews
|
2
2
|
class Config
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class << self
|
5
|
+
def merchant_group_id
|
6
|
+
@merchant_group_id
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def merchant_group_id=id
|
10
|
+
@merchant_group_id = id
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def site_id
|
14
|
+
@site_id
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
def site_id=id
|
18
|
+
@site_id = id
|
19
|
+
end
|
20
|
+
|
21
|
+
def review_data_path
|
22
|
+
@review_data_path || 'public/system/pwr'
|
23
|
+
end
|
24
|
+
|
25
|
+
def review_data_path=path
|
26
|
+
@review_data_path = path
|
27
|
+
end
|
28
|
+
|
18
29
|
end
|
19
30
|
|
20
31
|
end
|
data/lib/power_reviews/feed.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "faster_csv"
|
2
|
+
|
1
3
|
module PowerReviews
|
2
4
|
|
3
5
|
# Collects the feed data then outputs to CSV file for delivery to the power review peeps
|
@@ -28,8 +30,7 @@ module PowerReviews
|
|
28
30
|
end
|
29
31
|
|
30
32
|
def to_csv
|
31
|
-
|
32
|
-
FasterCSV.open("#{RAILS_ROOT}/tmp/power_reviews.csv", 'w') do |csv|
|
33
|
+
@csv ||= FasterCSV.generate do |csv|
|
33
34
|
csv << FeedItem.field_names
|
34
35
|
@items.each do |item|
|
35
36
|
csv << item.values
|
@@ -20,6 +20,11 @@ module PowerReviews
|
|
20
20
|
client.getbinaryfile(@config['zip'], to)
|
21
21
|
end
|
22
22
|
|
23
|
+
# Puts the data_feed on the specified ftp server
|
24
|
+
def copy_data_feed(from)
|
25
|
+
client.putbinaryfile(from, @config['data_feed'])
|
26
|
+
end
|
27
|
+
|
23
28
|
# do any cleanup necessary
|
24
29
|
def cleanup
|
25
30
|
@client.close
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
module PowerReviews
|
5
|
+
|
6
|
+
class ReviewData
|
7
|
+
|
8
|
+
class MissingData < StandardError; end;
|
9
|
+
|
10
|
+
DATA_FILES = ['review_data_complete', 'review_data_summary']
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
# retrieve the summary data for the given page_id
|
15
|
+
def summary(page_id)
|
16
|
+
document.summary(page_id)
|
17
|
+
rescue MissingData
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def reload!
|
22
|
+
@document = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def document
|
28
|
+
@document ||= new
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# initializes a new ReviewData document
|
35
|
+
def initialize(search_path=nil)
|
36
|
+
@search_path = search_path || PowerReviews::Config.review_data_path
|
37
|
+
end
|
38
|
+
|
39
|
+
def summary(page_id)
|
40
|
+
node = nil
|
41
|
+
summary_data.elements.each("//pageid") do |e|
|
42
|
+
node = e.parent if e.get_text == page_id
|
43
|
+
end
|
44
|
+
!node.nil? ? Summary.new(node) : nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def summary_data
|
48
|
+
@summary_data ||= read_document('review_data_summary')
|
49
|
+
end
|
50
|
+
|
51
|
+
def product_data
|
52
|
+
@product_data ||= read_document('review_data_complete')
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def read_document(name)
|
58
|
+
REXML::Document.new(File.new(xml_documents[name]))
|
59
|
+
end
|
60
|
+
|
61
|
+
def xml_documents
|
62
|
+
return @files unless @files.nil?
|
63
|
+
files = {}
|
64
|
+
Find.find(@search_path) do |path|
|
65
|
+
bn = File.basename(path, '.xml')
|
66
|
+
files[bn] = path if DATA_FILES.include?(bn)
|
67
|
+
end
|
68
|
+
missing = DATA_FILES.select { |f| files[f].blank? }
|
69
|
+
raise MissingData, "missing Power Reviews xml: #{missing.collect {|f| f + ".xml"}.join(', ')}" unless missing.empty?
|
70
|
+
@files = files
|
71
|
+
@files
|
72
|
+
end
|
73
|
+
|
74
|
+
class Summary
|
75
|
+
|
76
|
+
attr_reader :full_name, :average_rating, :reviews
|
77
|
+
|
78
|
+
def initialize(element)
|
79
|
+
@element = element
|
80
|
+
@full_name = text_for_element('name')
|
81
|
+
@average_rating = text_for_element('average_rating_decimal').to_s.to_f
|
82
|
+
@reviews = text_for_element('fullreviews').to_s.to_i
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def text_for_element(name)
|
88
|
+
element = nil
|
89
|
+
@element.each_element(name) { |e| element = e if element.nil? }
|
90
|
+
element.nil? ? '' : element.get_text
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end
|
data/lib/power_reviews/sync.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'power_reviews/protocols/base'
|
2
2
|
require 'power_reviews/protocols/cp'
|
3
3
|
require 'power_reviews/protocols/ftp'
|
4
|
+
require 'power_reviews/feed'
|
4
5
|
|
5
6
|
module PowerReviews
|
6
7
|
# Downloads the ftp file and stores it in the correct location unzipped
|
@@ -13,29 +14,44 @@ module PowerReviews
|
|
13
14
|
:ftp => Protocols::Ftp
|
14
15
|
}
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
class << self
|
18
|
+
|
19
|
+
# Execute the necessary actions
|
20
|
+
def execute
|
21
|
+
self.start do |client, config|
|
19
22
|
|
20
|
-
|
23
|
+
zip_path = "#{Rails.root}/public/system/reviews.zip"
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
unless client.done?
|
26
|
+
FileUtils.mkdir_p(File.dirname(zip_path))
|
27
|
+
# we need the correct path to be setup
|
28
|
+
client.copy_zip(zip_path)
|
29
|
+
`cd #{File.dirname(zip_path)} && unzip -o #{zip_path}`
|
30
|
+
client.done!
|
31
|
+
end
|
29
32
|
|
33
|
+
# zip up the powerreviews data tell the client to store it
|
34
|
+
data_path = "#{RAILS_ROOT}/tmp/review_data.csv"
|
35
|
+
File.open(data_path, 'w') do |f|
|
36
|
+
f.puts PowerReviews::Feed.process
|
37
|
+
end
|
38
|
+
client.copy_data_feed(data_path)
|
39
|
+
|
40
|
+
end
|
30
41
|
end
|
31
|
-
end
|
32
42
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
43
|
+
# Given the environment loads up the yaml file and creates a new instance
|
44
|
+
def start
|
45
|
+
config = self.configure
|
46
|
+
syncer = PROTOCOLS[config.delete('protocol').intern].new(config)
|
47
|
+
yield syncer, config
|
48
|
+
syncer.cleanup
|
49
|
+
end
|
50
|
+
|
51
|
+
def configure
|
52
|
+
@config ||= YAML::load(File.open("#{RAILS_ROOT}/config/power_reviews.yml"))[Rails.env] || {}
|
53
|
+
end
|
54
|
+
|
39
55
|
end
|
40
56
|
|
41
57
|
end
|
@@ -1,10 +1,51 @@
|
|
1
1
|
module PowerReviews
|
2
2
|
module ViewHelpers
|
3
|
+
|
4
|
+
# generates hReview compatible HTML for the given page_id
|
5
|
+
# renders the content as HTML at render time instead of relying
|
6
|
+
# on the Power Reviews javascript library to render the review content
|
7
|
+
def power_reviews_hreview(page_id, &blk)
|
8
|
+
|
9
|
+
summary = PowerReviews::ReviewData.summary(page_id)
|
10
|
+
|
11
|
+
if block_given?
|
12
|
+
yield summary unless summary.nil?
|
13
|
+
elsif !summary.nil?
|
3
14
|
|
4
|
-
|
5
|
-
|
15
|
+
<<-review
|
16
|
+
<div class='hreview-aggregate'>
|
17
|
+
<span class="item">
|
18
|
+
<span class="fn">#{summary.full_name}</span>
|
19
|
+
</span>
|
20
|
+
<span class="rating">
|
21
|
+
<span class="average">#{summary.average_rating}</span>
|
22
|
+
</span>
|
23
|
+
based on
|
24
|
+
<span class="count">#{summary.reviews}</span> user reviews.
|
25
|
+
</div>
|
26
|
+
review
|
27
|
+
else
|
28
|
+
''
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Includes the power reviews javascript, optionally provide the path to
|
33
|
+
# the javascript file if not installed in the default location
|
34
|
+
def power_reviews_javascript_tag(path_to_file = '/system/pwr/engine/js/full')
|
35
|
+
unless @power_reviews_javascript_needed.nil?
|
36
|
+
javascript_include_tag(path_to_file)
|
37
|
+
end
|
6
38
|
end
|
7
39
|
|
40
|
+
# Generates the javascript variables for a page that will be rendering
|
41
|
+
# PowerReviews elements
|
42
|
+
#
|
43
|
+
# Options:
|
44
|
+
#
|
45
|
+
# +:locale+ - default: en_US
|
46
|
+
# +:zip_location+ - where Power Reviews data is stored default: /system/
|
47
|
+
# +:pr_style_sheet - Location of custom Power Reviews stylesheet default: "" (empty string)
|
48
|
+
#
|
8
49
|
def power_reviews_javascript_variables(options = {})
|
9
50
|
options = {
|
10
51
|
:locale => 'en_US',
|
@@ -15,31 +56,65 @@ module PowerReviews
|
|
15
56
|
options.collect { |key, val| "var pr_#{key} = '#{val}';" unless val.blank? }.compact!.join("\n")
|
16
57
|
end
|
17
58
|
end
|
18
|
-
|
59
|
+
|
60
|
+
# Generates JavaScript to display the Power Reviews "snippet" element. Will show a summary
|
61
|
+
# of the reviews for the given +page_id+.
|
62
|
+
#
|
63
|
+
# Arguments:
|
64
|
+
# +page_id+ - the identifier for the product
|
65
|
+
# +write_review_url+ - the url to link to a page where the user can author a review
|
66
|
+
# +review_ancor+ - the url or anchor that links to the full reviews. Default: "#ReviewHeader"
|
19
67
|
def power_reviews_snippet(page_id, write_review_url, review_anchor = '#ReviewHeader')
|
68
|
+
@power_reviews_javascript_needed = true
|
20
69
|
javascript_tag do
|
21
70
|
<<-eos
|
22
|
-
POWERREVIEWS
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
71
|
+
if(POWERREVIEWS){
|
72
|
+
POWERREVIEWS.display.snippet(document, {
|
73
|
+
pr_page_id : '#{page_id}',
|
74
|
+
pr_write_review : '#{write_review_url}',
|
75
|
+
pr_read_review : '#{review_anchor}'
|
76
|
+
});
|
77
|
+
}
|
27
78
|
eos
|
28
79
|
end
|
29
80
|
end
|
30
|
-
|
81
|
+
|
82
|
+
# Displays the full reviews for the given +page_id+
|
83
|
+
#
|
84
|
+
# Arguments:
|
85
|
+
# +page_id+ - The identifier for the item to show reviews for
|
86
|
+
# +write_review_url+ - A url for a page where the user can write a review for the given product
|
31
87
|
def power_reviews_display(page_id, write_review_url)
|
88
|
+
@power_reviews_javascript_needed = true
|
32
89
|
javascript_tag do
|
33
90
|
<<-eos
|
34
|
-
POWERREVIEWS
|
35
|
-
|
36
|
-
|
37
|
-
|
91
|
+
if(POWERREVIEWS){
|
92
|
+
POWERREVIEWS.display.engine(document, {
|
93
|
+
pr_page_id : '#{page_id}',
|
94
|
+
pr_write_review : '#{write_review_url}'
|
95
|
+
});
|
96
|
+
}
|
38
97
|
eos
|
39
98
|
end
|
40
99
|
end
|
41
100
|
|
101
|
+
# Generates the javascript that renders the PowerReviews authoring form.
|
102
|
+
#
|
103
|
+
# Arguments:
|
104
|
+
# +page_id+ - The id of the item being reviewd
|
105
|
+
#
|
106
|
+
# Options:
|
107
|
+
# +:locale+ default ""
|
108
|
+
# +:site_id+ default: PowerReviews::Config.site_id
|
109
|
+
# +:merchant_group_id+ default: PowerReviews::Config.merchant_group_id
|
110
|
+
# +:source+ default: 'web'
|
111
|
+
# +:merchant_user_id+ default: ''
|
112
|
+
# +:merchant_user_email+ default: ''
|
113
|
+
# +:promo_code+ default: ''
|
114
|
+
# +:style_sheet+ default: ''
|
115
|
+
|
42
116
|
def power_reviews_form(page_id, options = {})
|
117
|
+
@power_reviews_javascript_needed = true
|
43
118
|
options = {
|
44
119
|
:locale => '',
|
45
120
|
:site_id => PowerReviews::Config.site_id,
|