solidus_recommendations 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21b4594ce7b4a73d27fad6e1ac72f35b8299aa79
4
+ data.tar.gz: cb32a9a47755eedc18e154fd74a7851ff281d69b
5
+ SHA512:
6
+ metadata.gz: 6f8b501c41c029c8d42278d0b05573a6d72d36f694c2f8f32e7e7fe71678ace70bc5dfb5cf5cdab17f398b0300084df6ae571981cf53254201a4f4f50f9bb25a
7
+ data.tar.gz: 11c8985246197158cfc3a9e1b3911cd8d11839349d07696cf78250b8dd40452604c5207aa7c9462574bd7b0b8e26dd3de234e8dd0ecc773e733bdcecf4b09897
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2017 [name of plugin creator]
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Spree nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ SolidusRecommendations
2
+ ======================
3
+
4
+ Uses Elasticsearch on top of Solidus framework to retrieve relevant recommendations based on what users have purchased in the past.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ Add solidus_recommendations to your Gemfile:
10
+
11
+ ```ruby
12
+ gem 'solidus_recommendations'
13
+ ```
14
+
15
+ Bundle your dependencies and run the installation generator:
16
+
17
+ ```shell
18
+ bundle
19
+ bundle exec rails g solidus_recommendations:install
20
+ ```
21
+
22
+ Usage
23
+ -----
24
+
25
+ We can get recommendations based on the product `123` by doing the following:
26
+ ```ruby
27
+ Spree::Product.recommendations.get(123)
28
+ ```
29
+
30
+ The query defaults to at most 10 results, If you want more or less then you can use the `size` argument.
31
+ ```ruby
32
+ Spree::Product.recommendations.get(123, size: 5) # At most 5 results.
33
+ ```
34
+
35
+ (Experimental) Currently we index the products a user has purchased as well as the products within each order. These two indices can say different things about our data. The user index gives results for "What did other users purchase that also purchased this product". The order index is for "What did other users checkout with that also checked out with this product". By default the user index is used to query for recommendations but that can be changed using the `index` argument. Acceptable values are `[:user, :order]`.
36
+ ```ruby
37
+ Spree::Product.recommendations.get(123, index: :order)
38
+ ```
39
+
40
+ Testing
41
+ -------
42
+
43
+ Install [elasticsearch](https://www.elastic.co/downloads/elasticsearch), this is needed for rspec tests. If you have issues running tests, see [https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-extensions#testcluster](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-extensions#testcluster)
44
+
45
+ First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs, and [Rubocop](https://github.com/bbatsov/rubocop) static code analysis. The dummy app can be regenerated by using `rake test_app`.
46
+
47
+ ```shell
48
+ bundle
49
+ bundle exec rake
50
+ ```
51
+
52
+ When testing your applications integration with this extension you may use it's factories.
53
+ Simply add this require statement to your spec_helper:
54
+
55
+ ```ruby
56
+ require 'solidus_recommendations/factories'
57
+ ```
58
+
59
+ Copyright (c) 2017 [name of extension creator], released under the New BSD License
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require 'bundler'
2
+
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ begin
6
+ require 'spree/testing_support/extension_rake'
7
+ require 'rubocop/rake_task'
8
+ require 'rspec/core/rake_task'
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ RuboCop::RakeTask.new
13
+
14
+ task default: %i(first_run rubocop spec)
15
+ rescue LoadError
16
+ # no rspec available
17
+ end
18
+
19
+ task :first_run do
20
+ if Dir['spec/dummy'].empty?
21
+ Rake::Task[:test_app].invoke
22
+ Dir.chdir('../../')
23
+ end
24
+ end
25
+
26
+ desc 'Generates a dummy app for testing'
27
+ task :test_app do
28
+ ENV['LIB_NAME'] = 'solidus_recommendations'
29
+ Rake::Task['extension:test_app'].invoke
30
+ end
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/backend/all.js'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/frontend/all.js'
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/frontend/all.css'
4
+ */
@@ -0,0 +1,38 @@
1
+ module Spree
2
+ module Callbackable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Elasticsearch::Model
7
+
8
+ after_commit :index_document, on: :create
9
+ after_commit :update_document, on: :update
10
+ after_commit :delete_document, on: :destroy
11
+
12
+ delegate :delete_document, to: :__elasticsearch__
13
+
14
+ ##
15
+ # Index document into elasticsearch
16
+ #
17
+ def index_document
18
+ __elasticsearch__.index_document(version_options)
19
+ end
20
+
21
+ ##
22
+ # Updates elasticsearch document from featured model
23
+ #
24
+ def update_document
25
+ __elasticsearch__.update_document(version_options)
26
+ end
27
+
28
+ private
29
+
30
+ def version_options
31
+ {
32
+ version: (updated_at.to_f * 1000).to_i, # Include Milliseconds
33
+ version_type: 'external'
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module Indexable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ ##
7
+ # Override Index naming to add environment
8
+ index_name index_name "#{name.gsub('::', '-').downcase}-#{Rails.env}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ module Spree
2
+ class Order
3
+ module Indexable
4
+ extend ActiveSupport::Concern
5
+
6
+ ELASTICSEARCH_SETTINGS = {
7
+ analysis: {
8
+ analyzer: {
9
+ keyword_lowercase: {
10
+ tokenizer: 'keyword',
11
+ filter: ['lowercase']
12
+ }
13
+ }
14
+ }
15
+ }
16
+
17
+ included do
18
+ include Spree::Indexable
19
+
20
+ ##
21
+ # Define Order mapping for Elasticserach index
22
+ #
23
+ settings ELASTICSEARCH_SETTINGS do
24
+ mappings dynamic: false do
25
+ indexes :product_ids, type: 'integer'
26
+ indexes :created_at, type: 'date'
27
+ indexes :completed_at, type: 'date'
28
+ end
29
+ end
30
+
31
+ ##
32
+ # Formats hash for elasticsearch.
33
+ #
34
+ def as_indexed_json(_options = {})
35
+ as_json only: [:created_at, :completed_at],
36
+ methods: [:product_ids]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ module Spree
2
+ class Product
3
+ module Recommendable
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ ##
8
+ # Get recommendations for products.
9
+ # @return [Recommendations::Recommendable::Products]
10
+ #
11
+ def recommendations
12
+ @recommend_client ||= SolidusRecommendations::Client.new
13
+ @recommend_client.products
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ module Spree
2
+ class User
3
+ module Indexable
4
+ extend ActiveSupport::Concern
5
+
6
+ ELASTICSEARCH_SETTINGS = {
7
+ analysis: {
8
+ analyzer: {
9
+ keyword_lowercase: {
10
+ tokenizer: 'keyword',
11
+ filter: ['lowercase']
12
+ }
13
+ }
14
+ }
15
+ }
16
+
17
+ included do
18
+ include Spree::Indexable
19
+
20
+ ##
21
+ # Define Order mapping for Elasticserach index
22
+ #
23
+ settings ELASTICSEARCH_SETTINGS do
24
+ mappings dynamic: false do
25
+ indexes :purchased_product_ids, type: 'integer'
26
+ indexes :created_at, type: 'date'
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Formats hash for elasticsearch.
32
+ #
33
+ def as_indexed_json(_options = {})
34
+ as_json methods: [:purchased_product_ids]
35
+ end
36
+
37
+ private
38
+
39
+ def purchased_product_ids
40
+ orders.map(&:product_ids).flatten.uniq
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,2 @@
1
+ Spree::Order.include Spree::Callbackable
2
+ Spree::Order.include Spree::Order::Indexable
@@ -0,0 +1,2 @@
1
+ Spree.user_class.include Spree::Callbackable
2
+ Spree.user_class.include Spree::User::Indexable
@@ -0,0 +1,5 @@
1
+ # Sample localization file for English. Add more files in this directory for other locales.
2
+ # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
+
4
+ en:
5
+ hello: Hello world
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Spree::Core::Engine.routes.draw do
2
+ # Add your extension routes here
3
+ end
@@ -0,0 +1,30 @@
1
+ module SolidusRecommendations
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ class_option :auto_run_migrations, type: :boolean, default: false
5
+
6
+ def add_javascripts
7
+ append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_recommendations\n"
8
+ append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_recommendations\n"
9
+ end
10
+
11
+ def add_stylesheets
12
+ inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_recommendations\n", before: /\*\//, verbose: true
13
+ inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_recommendations\n", before: /\*\//, verbose: true
14
+ end
15
+
16
+ def add_migrations
17
+ run 'bundle exec rake railties:install:migrations FROM=solidus_recommendations'
18
+ end
19
+
20
+ def run_migrations
21
+ run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
22
+ if run_migrations
23
+ run 'bundle exec rake db:migrate'
24
+ else
25
+ puts 'Skipping rake db:migrate, don\'t forget to run it!'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module SolidusRecommendations
2
+ class Client
3
+ ##
4
+ # Defines a method to access class instance.
5
+ #
6
+ # @example Create a namespace for products
7
+ # add_recommendable :products #=> SolidusRecommendations::Client::Products.new
8
+ #
9
+ def self.add_recommendable(name)
10
+ converted = name.to_s.split('_').map(&:capitalize).join
11
+ klass = SolidusRecommendations::Recommendable.const_get(converted)
12
+ create_instance(klass)
13
+ end
14
+
15
+ ##
16
+ # Dynamically creates an attr_reader for each client space
17
+ # and sets it to the initalized values
18
+ #
19
+ def self.create_instance(klass)
20
+ reader = klass.to_s.split('::').last.downcase
21
+ define_method(reader.to_sym) { klass.new }
22
+ end
23
+
24
+ ##
25
+ # Methods for product recommendations.
26
+ #
27
+ # @return [SolidusRecommendations::Recommendable::Products]
28
+ #
29
+ add_recommendable :products
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module SolidusRecommendations
2
+ class Engine < Rails::Engine
3
+ require 'spree/core'
4
+ isolate_namespace Spree
5
+ engine_name 'solidus_recommendations'
6
+
7
+ # use rspec for tests
8
+ config.generators do |g|
9
+ g.test_framework :rspec
10
+ end
11
+
12
+ def self.activate
13
+ Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
14
+ Rails.configuration.cache_classes ? require(c) : load(c)
15
+ end
16
+ end
17
+
18
+ config.to_prepare(&method(:activate).to_proc)
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module SolidusRecommendations
2
+ module Errors
3
+ class Standard < StandardError
4
+ def initialize(msg = MESSAGES[self.class])
5
+ end
6
+ end
7
+
8
+ class NonSupportedIndex < Standard; end
9
+
10
+ MESSAGES = {
11
+ NonSupportedIndex => 'The index specified is not supported.'
12
+ }
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ # Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
3
+ #
4
+ # Example adding this to your spec_helper will load these Factories for use:
5
+ # require 'solidus_recommendations/factories'
6
+ end
@@ -0,0 +1,41 @@
1
+ module SolidusRecommendations
2
+ module Recommendable
3
+ class Base
4
+ protected
5
+
6
+ ##
7
+ # Converts an Array of models to an array of their ids.
8
+ # If the array is already the ids then nothing happens.
9
+ #
10
+ # @param [Array<Object, Integer>] items The array to convert to integers reprsenting model ids.
11
+ # @return [Array<Integer>] An array of model ids.
12
+ #
13
+ def convert_to_id(items)
14
+ items.map { |item| item.respond_to?(:id) ? item.id : item }
15
+ end
16
+
17
+ ##
18
+ # Converts significant_terms aggregation buckets to
19
+ # their respective models.
20
+ #
21
+ # @param [Object] aggregation The response from elasticsearch search query.
22
+ # @param [Array<Integer>] excluded_ids The ids to exclude from results.
23
+ # @param [Object] klass The respective model class.
24
+ #
25
+ # @return [Array<klass>] An array of the respective models.
26
+ #
27
+ def from_significant_terms(aggregation, excluded_ids, klass)
28
+ items = []
29
+ aggregation.buckets.each do |bucket|
30
+ next if excluded_ids.include?(bucket[:key])
31
+ item = klass.find_by(id: bucket[:key])
32
+ next if item.nil?
33
+
34
+ items << item
35
+ end
36
+
37
+ items
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,98 @@
1
+ module SolidusRecommendations
2
+ module Recommendable
3
+ ##
4
+ # Provides methods to get recommended products based on certain criteria
5
+ # such as "Bought Together" or "Users also bought"
6
+ #
7
+ class Products < Base
8
+ ##
9
+ # Acceptable indices to pass as index option
10
+ # to methods
11
+ #
12
+ ACCEPTED_INDICES = [:user, :order]
13
+
14
+ ##
15
+ # Gets recommended products
16
+ #
17
+ # @example Get recommended products based on user index.
18
+ # product = Spree::Product.find(4)
19
+ # recommended = SolidusRecommendations::Client.new
20
+ # recommended.products.get(product)
21
+ #
22
+ # # Good for getting recommendations based on what other users have
23
+ # # have purchased.
24
+ #
25
+ # @example Get recommended products based on order index.
26
+ # product = Spree::Product.find(4)
27
+ # recommmended = SolidusRecommendations::Client.new
28
+ # recommended.products.get(product, index: :order)
29
+ #
30
+ # # Good for getting recommendations based on what others checkout with
31
+ # # frequently.
32
+ #
33
+ # @param [Spree::Product, Integer] product The product to base recommendations off of.
34
+ # @param [Hash] options
35
+ # @option options [Symbol, String] :index The index to perform aggregation on. (*Defaults to :user*)
36
+ # @option options [Integer] :size The number of recommendations to return. (*Defaults to 10*)
37
+ #
38
+ # @return [Array<Spree::Product]
39
+ #
40
+ def get(product, options = {})
41
+ return [] if product.nil?
42
+
43
+ options.deep_symbolize_keys!
44
+ index = options.delete(:index) || :user
45
+ size = options.delete(:size) || 10
46
+
47
+ # If index is not supported then we will get a weird undefined
48
+ # method error. This error will make more sense.
49
+ raise Errors::NonSupportedIndex unless ACCEPTED_INDICES.include?(index.to_sym)
50
+
51
+ product = convert_to_id([product]).first
52
+ aggs = send("#{index}_index_significant_terms", product, size)
53
+
54
+ from_significant_terms(aggs, [product], Spree::Product)
55
+ end
56
+
57
+ private
58
+
59
+ def order_index_significant_terms(product, size = 10)
60
+ payload = significant_terms_query('product_ids', product, size)
61
+ response = Spree::Order.__elasticsearch__.search(payload)
62
+
63
+ response.aggregations.recommended
64
+ end
65
+
66
+ def user_index_significant_terms(product, size = 10)
67
+ payload = significant_terms_query('purchased_product_ids', product, size)
68
+ response = Spree.user_class.__elasticsearch__.search(payload)
69
+
70
+ response.aggregations.recommended
71
+ end
72
+
73
+ ##
74
+ # Builds body for significant terms aggregation.
75
+ #
76
+ def significant_terms_query(field, value, size)
77
+ {
78
+ size: 0,
79
+ query: {
80
+ bool: {
81
+ filter: [
82
+ { term: { "#{field}": value } }
83
+ ]
84
+ }
85
+ },
86
+ aggregations: {
87
+ recommended: {
88
+ significant_terms: {
89
+ field: field,
90
+ size: size + 1
91
+ }
92
+ }
93
+ }
94
+ }
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,3 @@
1
+ module SolidusRecommendations
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,8 @@
1
+ require 'solidus_core'
2
+ require 'elasticsearch/model'
3
+ require 'solidus_recommendations/engine'
4
+
5
+ require 'solidus_recommendations/recommendable/base'
6
+ require 'solidus_recommendations/recommendable/products'
7
+ require 'solidus_recommendations/errors'
8
+ require 'solidus_recommendations/client'
metadata ADDED
@@ -0,0 +1,292 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solidus_recommendations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Taylor Scott
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: solidus_core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: elasticsearch-model
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: capybara
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: poltergeist
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coffee-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sass-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: database_cleaner
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: factory_girl
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec-rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec-its
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop-rspec
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: simplecov
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: sqlite3
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: pry
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: elasticsearch-extensions
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ description: Recommendations for Solidus using Elasticsearch significant terms aggregation
238
+ email: t.skukx@gmail.com
239
+ executables: []
240
+ extensions: []
241
+ extra_rdoc_files: []
242
+ files:
243
+ - LICENSE
244
+ - README.md
245
+ - Rakefile
246
+ - app/assets/javascripts/spree/backend/solidus_recommendations.js
247
+ - app/assets/javascripts/spree/frontend/solidus_recommendations.js
248
+ - app/assets/stylesheets/spree/backend/solidus_recommendations.css
249
+ - app/assets/stylesheets/spree/frontend/solidus_recommendations.css
250
+ - app/models/concerns/spree/callbackable.rb
251
+ - app/models/concerns/spree/indexable.rb
252
+ - app/models/concerns/spree/order/indexable.rb
253
+ - app/models/concerns/spree/product/recommendable.rb
254
+ - app/models/concerns/spree/user/indexable.rb
255
+ - app/models/spree/order_decorator.rb
256
+ - app/models/spree/user_decorator.rb
257
+ - config/locales/en.yml
258
+ - config/routes.rb
259
+ - lib/generators/solidus_recommendations/install/install_generator.rb
260
+ - lib/solidus_recommendations.rb
261
+ - lib/solidus_recommendations/client.rb
262
+ - lib/solidus_recommendations/engine.rb
263
+ - lib/solidus_recommendations/errors.rb
264
+ - lib/solidus_recommendations/factories.rb
265
+ - lib/solidus_recommendations/recommendable/base.rb
266
+ - lib/solidus_recommendations/recommendable/products.rb
267
+ - lib/solidus_recommendations/version.rb
268
+ homepage: https://github.com/skukx
269
+ licenses:
270
+ - BSD-3-Clause
271
+ metadata: {}
272
+ post_install_message:
273
+ rdoc_options: []
274
+ require_paths:
275
+ - lib
276
+ required_ruby_version: !ruby/object:Gem::Requirement
277
+ requirements:
278
+ - - ">="
279
+ - !ruby/object:Gem::Version
280
+ version: '0'
281
+ required_rubygems_version: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ requirements: []
287
+ rubyforge_project:
288
+ rubygems_version: 2.5.1
289
+ signing_key:
290
+ specification_version: 4
291
+ summary: Recommendations for Solidus
292
+ test_files: []