meducation_sdk 1.5.7 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 59cdaa5f76cdde2eb332690eda73a06fc48f7679
4
- data.tar.gz: 954e3a4ecf08267207ccea0751c0896d719bf8f6
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NGJlOWVmZDZhOTE1NDRhY2M5ODcyYzgzYTE0ZDVkNWY1NDJkYTZiYw==
5
+ data.tar.gz: !binary |-
6
+ ZjI3NzAzODg0YzExMzA5ZTczZGMwYmY0ZTZkMzViMDM5NjYyYTdlZA==
5
7
  SHA512:
6
- metadata.gz: 1e5e383e3455c0109d8399762c5dcf73deedbfa7e234a0e18913c2caeb702fe5c2a0a116a2e40116ebc022bf55a8c946f35436b4ca3b378f40a5d22cc6beca6b
7
- data.tar.gz: 6e468ec9dfe67820d6857ead5038651b2985024d5e2d9969030dd53ce00169bce7a101f40ebfca5413ba6c4c3f7317d84cf11c6c4f0d396c2048844c88059fc3
8
+ metadata.gz: !binary |-
9
+ M2ZhNTUyMjZmMzU2NDMyYTZkYWMzZjQ3MzcwN2FkYWI3NGJkOTMwODI0N2I4
10
+ ZDliZWFmMGE2MzMxMzJiNjdkZTdhNWEzNjhkZjlhODNiZDVlYzMyMjAxZWNl
11
+ ZDUwODc2NzkwMGRhMzgwNjczMDNkMTBjODBiZTY1YTIyMjM2Mzg=
12
+ data.tar.gz: !binary |-
13
+ NzNhYjJhYTNjYTFjNTMyZWY0NTMxMGM3OTI0ZDVlMGZiN2RhNDM4NjJkNjA2
14
+ M2RiMGUwYWIzYzE5NGUyNTEyZjRkZWIxZmIyOTQwOWUxZTZiNDJiMGMyNWZl
15
+ NmUyYTVlNDFlNmU5Y2QzOTRmNjgwYmM3MWZiNDcxOGJhYWYwNDE=
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- # 1.5.7 / 2014-03-4
1
+ # 1.6.0 / 2014-03-07
2
+ * [FEATURE] Add recommender
3
+ * [FEATURE] Change routing to spi.meducation.net
4
+
5
+ # 1.5.7 / 2014-03-04
2
6
  * [FEATURE] Add authors to to collection topics
3
7
 
4
8
  # 1.5.6 / 2014-02-27
@@ -5,62 +5,9 @@ require "meducation_sdk/version"
5
5
  require "meducation_sdk/configuration"
6
6
  require "meducation_sdk/mocker"
7
7
 
8
+ require "meducation_sdk/helpers"
9
+ require "meducation_sdk/services/recommender"
8
10
  require "meducation_sdk/resource"
9
- require "meducation_sdk/resources/badges/badge"
10
-
11
- RESOURCES = %w{
12
- author
13
- badges/answerer_badge
14
- badges/befriender_badge
15
- badges/citizen_badge
16
- badges/commentator_badge
17
- badges/community_member_badge
18
- badges/contributor_badge
19
- badges/eminent_author_badge
20
- badges/enlightener_badge
21
- badges/inquisitive_mind_badge
22
- badges/photogenic_badge
23
- badges/questioner_badge
24
- badges/respected_author_badge
25
- blog_post
26
- blogger
27
- board
28
- board_follow
29
- board_item
30
- collection
31
- collection_section
32
- collection_topic
33
- comment
34
- community
35
- community_membership
36
- dashboard_item
37
- ecommerce_subscription
38
- external_resource
39
- friendship
40
- group
41
- group_discussion
42
- group_discussion_post
43
- group_invite
44
- group_membership
45
- knowledge_bank_question
46
- knowledge_bank_answer
47
- media_file
48
- mesh_heading
49
- message
50
- message_thread
51
- message_thread_contributor
52
- mnemonic
53
- notification
54
- partner
55
- syllabus_item
56
- user
57
- user_email_data
58
- user_settings
59
- vote
60
- }
61
- RESOURCES.each do |resource|
62
- require "meducation_sdk/resources/#{resource}"
63
- end
64
11
 
65
12
  module MeducationSDK
66
13
  def self.config
@@ -6,7 +6,10 @@ module MeducationSDK
6
6
 
7
7
  class Configuration
8
8
 
9
- SETTINGS = [ :logger ]
9
+ SETTINGS = [
10
+ :logger,
11
+ :recommender_host, :recommender_port
12
+ ]
10
13
 
11
14
  attr_writer *SETTINGS
12
15
 
@@ -14,11 +17,14 @@ module MeducationSDK
14
17
  self.logger = Filum.logger
15
18
 
16
19
  Loquor.config do |config|
17
- config.endpoint = "http://www.meducation.net/system"
20
+ config.endpoint = "http://spi.meducation.net"
18
21
  config.substitute_values[true] = ":__true__"
19
22
  config.substitute_values[false] = ":__false__"
20
23
  config.retry_404s = true
21
24
  end
25
+
26
+ self.recommender_host = "recommender.meducation.net"
27
+ self.recommender_port = 4567
22
28
  end
23
29
 
24
30
  [:access_id, :secret_key, :endpoint, :cache].each do |setting|
@@ -0,0 +1,26 @@
1
+ module MeducationSDK
2
+ module Helpers
3
+ SDK_TO_SPI_MAPPINGS = {}
4
+
5
+ def sdk_class_for(spi_type)
6
+ sdk_type_for(spi_type).constantize
7
+ end
8
+
9
+ def sdk_type_for(spi_type)
10
+ if SDK_TO_SPI_MAPPINGS.has_value?(spi_type)
11
+ SDK_TO_SPI_MAPPINGS.key(spi_type)
12
+ else
13
+ "MeducationSDK::#{spi_type.gsub("::", "")}"
14
+ end
15
+ end
16
+
17
+ def spi_type_for(sdk_type)
18
+ if SDK_TO_SPI_MAPPINGS.has_key?(sdk_type)
19
+ SDK_TO_SPI_MAPPINGS[sdk_type]
20
+ else
21
+ sdk_type.gsub("MeducationSDK::", "")
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -1,5 +1,11 @@
1
1
  module MeducationSDK
2
2
  class Resource < Loquor::Resource
3
+ include Helpers
4
+
5
+ def self.spi_type=(type)
6
+ Helpers::SDK_TO_SPI_MAPPINGS[self.name] = type
7
+ end
8
+
3
9
  def created_at
4
10
  DateTime.parse(@data[:created_at])
5
11
  end
@@ -7,14 +13,61 @@ module MeducationSDK
7
13
  def updated_at
8
14
  DateTime.parse(@data[:updated_at])
9
15
  end
10
-
11
- def class_for(meducation_type)
12
- case meducation_type
13
- when "Item::Comment"
14
- Comment
15
- else
16
- "MeducationSDK::#{meducation_type.gsub("::", "")}".constantize
17
- end
18
- end
19
16
  end
20
17
  end
18
+
19
+ RESOURCES = %w{
20
+ author
21
+ badges/answerer_badge
22
+ badges/befriender_badge
23
+ badges/citizen_badge
24
+ badges/commentator_badge
25
+ badges/community_member_badge
26
+ badges/contributor_badge
27
+ badges/eminent_author_badge
28
+ badges/enlightener_badge
29
+ badges/inquisitive_mind_badge
30
+ badges/photogenic_badge
31
+ badges/questioner_badge
32
+ badges/respected_author_badge
33
+ blog_post
34
+ blogger
35
+ board
36
+ board_follow
37
+ board_item
38
+ collection
39
+ collection_section
40
+ collection_topic
41
+ comment
42
+ community
43
+ community_membership
44
+ dashboard_item
45
+ ecommerce_subscription
46
+ external_resource
47
+ friendship
48
+ group
49
+ group_discussion
50
+ group_discussion_post
51
+ group_invite
52
+ group_membership
53
+ knowledge_bank_question
54
+ knowledge_bank_answer
55
+ media_file
56
+ mesh_heading
57
+ message
58
+ message_thread
59
+ message_thread_contributor
60
+ mnemonic
61
+ notification
62
+ partner
63
+ syllabus_item
64
+ user
65
+ user_email_data
66
+ user_settings
67
+ vote
68
+ }
69
+
70
+ require "meducation_sdk/resources/badges/badge"
71
+ RESOURCES.each do |resource|
72
+ require "meducation_sdk/resources/#{resource}"
73
+ end
@@ -3,7 +3,7 @@ module MeducationSDK
3
3
  self.path = "/boards"
4
4
 
5
5
  def owner
6
- @owner ||= class_for(owner_type).find(owner_id)
6
+ @owner ||= sdk_class_for(owner_type).find(owner_id)
7
7
  end
8
8
 
9
9
  def created_by
@@ -3,7 +3,7 @@ module MeducationSDK
3
3
  self.path = "/board_items"
4
4
 
5
5
  def item
6
- @item ||= class_for(item_type).find(item_id)
6
+ @item ||= sdk_class_for(item_type).find(item_id)
7
7
  end
8
8
 
9
9
  def board
@@ -1,9 +1,10 @@
1
1
  module MeducationSDK
2
2
  class Comment < Resource
3
3
  self.path = "/comments"
4
+ self.spi_type = "Item::Comment"
4
5
 
5
6
  def item
6
- @item ||= class_for(item_type).find(item_id)
7
+ @item ||= sdk_class_for(item_type).find(item_id)
7
8
  end
8
9
 
9
10
  def user
@@ -7,7 +7,7 @@ module MeducationSDK
7
7
  end
8
8
 
9
9
  def item
10
- @item ||= class_for(item_type).find(item_id)
10
+ @item ||= sdk_class_for(item_type).find(item_id)
11
11
  end
12
12
  end
13
13
 
@@ -1,6 +1,7 @@
1
1
  module MeducationSDK
2
2
  class KnowledgeBankQuestion < Resource
3
3
  self.path = "/knowledge_bank_questions"
4
+ self.spi_type = "KnowledgeBank::Question"
4
5
 
5
6
  def user
6
7
  @user = User.find(user_id)
@@ -3,7 +3,7 @@ module MeducationSDK
3
3
  self.path = "/notifications"
4
4
 
5
5
  def item
6
- @item ||= class_for(item_type).find(item_id)
6
+ @item ||= sdk_class_for(item_type).find(item_id)
7
7
  end
8
8
 
9
9
  def user
@@ -1,9 +1,10 @@
1
1
  module MeducationSDK
2
2
  class Vote < Resource
3
3
  self.path = "/votes"
4
+ self.spi_type = "Item::Vote"
4
5
 
5
6
  def item
6
- @item ||= class_for(item_type).find(item_id)
7
+ @item ||= sdk_class_for(item_type).find(item_id)
7
8
  end
8
9
 
9
10
  def user
@@ -0,0 +1,70 @@
1
+ module MeducationSDK
2
+ class Recommender
3
+ include Helpers
4
+
5
+ def self.recommend(item, options = {})
6
+ new(item, options).recommend
7
+ end
8
+
9
+ attr_reader :item
10
+ def initialize(item, options = {})
11
+ @item = item
12
+ @options = options
13
+ end
14
+
15
+ def recommend
16
+ generate_recommendations
17
+ rescue => e
18
+ log_error("!!Recommender Error!!")
19
+ log_error(e.message)
20
+ log_error(e.backtrace)
21
+ #Item::Recommendation.where(item_type: @item.class.name).where(item_id: @item.id).includes(:recommendation).map(&:recommendation)
22
+ []
23
+ end
24
+
25
+ def generate_recommendations
26
+ groupings = {}
27
+ correct_order = recommender_results.map do |result|
28
+ groupings[result['type']] ||= []
29
+ groupings[result['type']] << result['id']
30
+ "#{result['type']}##{result['id']}"
31
+ end
32
+
33
+ output = groupings.map {|(type, ids)| sdk_class_for(type).where(id: ids) }.flatten
34
+ output.sort_by!{ |item| correct_order.index("#{item.class.name}##{item.id}") }
35
+ output
36
+ end
37
+
38
+ def recommender_results
39
+ @recommender_results ||= begin
40
+ results = JSON.parse(recommender_json)
41
+ if @options[:limit]
42
+ results[0..(@options[:limit] - 1)]
43
+ else
44
+ results
45
+ end
46
+ end
47
+ end
48
+
49
+ def recommender_json
50
+ path = "/#{spi_type_for(item.class.name)}/#{item.id}"
51
+ log "Calling #{config.recommender_host}:#{config.recommender_host}#{path}"
52
+ response = Net::HTTP.get_response(config.recommender_host, path, config.recommender_port)
53
+ body = response.body
54
+ log "Received #{body}"
55
+ body
56
+ end
57
+
58
+ def log(*args)
59
+ config.logger.info(*args)
60
+ end
61
+
62
+ def log_error(*args)
63
+ config.logger.error(*args)
64
+ end
65
+
66
+ def config
67
+ MeducationSDK.config
68
+ end
69
+ end
70
+ end
@@ -1,3 +1,3 @@
1
1
  module MeducationSDK
2
- VERSION = "1.5.7"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -22,10 +22,10 @@ module MeducationSDK
22
22
 
23
23
  def test_endpoint_is_set_correctly
24
24
  Configuration.new
25
- assert_equal "http://www.meducation.net/system", Loquor.config.endpoint
25
+ assert_equal "http://spi.meducation.net", Loquor.config.endpoint
26
26
  end
27
27
 
28
- def test_endpoint_is_set_correctly
28
+ def test_retry_404s_is_set_correctly
29
29
  Configuration.new
30
30
  assert_equal true, Loquor.config.retry_404s
31
31
  end
@@ -0,0 +1,23 @@
1
+ require_relative 'test_helper'
2
+ module MeducationSDK
3
+ class HelperTestClass
4
+ include Helpers
5
+ end
6
+
7
+ class HelpersTest < Minitest::Test
8
+ {
9
+ "Item::Comment" => "MeducationSDK::Comment",
10
+ "KnowledgeBank::Question" => "MeducationSDK::KnowledgeBankQuestion"
11
+ }.each do |spi_type, sdk_type|
12
+ define_method "test_sdk_type_for_#{spi_type.underscore.gsub("/", "_")}" do
13
+ assert_equal sdk_type, HelperTestClass.new.sdk_type_for(spi_type)
14
+ end
15
+ define_method "test_sdk_class_for_#{spi_type.underscore.gsub("/", "_")}" do
16
+ assert_equal sdk_type.constantize, HelperTestClass.new.sdk_class_for(spi_type)
17
+ end
18
+ define_method "test_spi_type_for_#{spi_type.underscore.gsub("/", "_")}" do
19
+ assert_equal spi_type, HelperTestClass.new.spi_type_for(sdk_type)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -17,15 +17,8 @@ module MeducationSDK
17
17
  end
18
18
  end
19
19
  end
20
-
21
- {
22
- "Item::Comment" => Comment,
23
- "KnowledgeBank::Question" => KnowledgeBankQuestion
24
- }.each do |meducation_type, sdk_class|
25
- define_method "test_class_for_#{meducation_type.underscore.gsub("/", "_")}" do
26
- r = Resource.new({})
27
- assert_equal sdk_class, r.class_for(meducation_type)
28
- end
20
+ define_method "test_helpers_included" do
21
+ assert Resource.new({}).respond_to?(:sdk_class_for)
29
22
  end
30
23
 
31
24
  def test_created_at_is_a_datetime
@@ -0,0 +1,72 @@
1
+ require_relative '../test_helper'
2
+
3
+ module MeducationSDK
4
+ class RecommenderTest < Minitest::Test
5
+
6
+ def empty_response
7
+ mock(body: '[]')
8
+ end
9
+
10
+ def item
11
+ @item ||= MediaFile.new({id: 10})
12
+ end
13
+
14
+ def item2
15
+ @item2 ||= MediaFile.new({id: 56})
16
+ end
17
+
18
+ def test_should_call_new
19
+ Recommender.expects(:new).with(item, {}).returns(mock(recommend: nil))
20
+ Recommender.recommend(item)
21
+ end
22
+
23
+ def test_should_proxy_to_recommend
24
+ Recommender.any_instance.expects(:recommend)
25
+ Recommender.recommend(nil)
26
+ end
27
+
28
+ def test_should_call_the_recommender_service
29
+ Net::HTTP.expects(:get_response).with("recommender.meducation.net", "/MediaFile/#{item.id}", 4567).returns(empty_response)
30
+ Recommender.new(item).recommend
31
+ end
32
+
33
+ def test_should_call_parse_results_of_recommendation_service
34
+ json = [
35
+ {"type" => "MediaFile", "id" => item.id, "score" => 0.0097},
36
+ {"type" => "MediaFile", "id" => item2.id, "score" => 0.0078}
37
+ ].to_json
38
+
39
+ Net::HTTP.expects(:get_response).returns(mock(body: json))
40
+ MediaFile.expects(:where).with({id: [item.id, item2.id]}).returns([item, item2])
41
+ items = Recommender.new(item).recommend
42
+ assert_equal [item, item2], items
43
+ end
44
+
45
+ def test_should_limit_correctly
46
+ items = 6.times.map { |x| MediaFile.new({id: x}) }
47
+ json = items.map {|item| {"type" => "MediaFile", "id" => item.id, "score" => 0.0097} }.to_json
48
+
49
+ Net::HTTP.expects(:get_response).returns(mock(body: json))
50
+ MediaFile.expects(:where).with({id: items[0..2].map(&:id)}).returns(items[0..2])
51
+ results = Recommender.new(item, limit: 3).recommend
52
+ end
53
+
54
+ def test_should_log_an_exception
55
+ Net::HTTP.expects(:get_response).raises(StandardError)
56
+ MeducationSDK.config.logger.expects(:error).with("!!Recommender Error!!")
57
+ MeducationSDK.config.logger.expects(:error).with("StandardError")
58
+ Recommender.new(item).recommend
59
+ end
60
+
61
+ def test_should_catch_an_exception_and_render_backup_recommendations
62
+ skip
63
+ recommendation = Item::Recommendation.create!(
64
+ item_type: item.class.name, item_id: item.id, jaccard_similarity: 1,
65
+ recommendation_type: item2.class.name, recommendation_id: item2.id
66
+ )
67
+ Net::HTTP.expects(:get_response).raises(StandardError)
68
+ items = Recommender.new(item).recommend
69
+ assert_equal [item2], items
70
+ end
71
+ end
72
+ end
data/test/test_helper.rb CHANGED
@@ -23,7 +23,7 @@ class Minitest::Test
23
23
  config.logger = MeducationSDK.config.logger
24
24
  config.access_id = "Sermo"
25
25
  config.secret_key = "foobar"
26
- config.endpoint = "http://localhost:3000/system"
26
+ config.endpoint = "http://localhost:3000/spi"
27
27
  end
28
28
  end
29
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meducation_sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.7
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Walker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-04 00:00:00.000000000 Z
11
+ date: 2014-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -70,14 +70,14 @@ dependencies:
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ! '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ! '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
@@ -98,14 +98,14 @@ dependencies:
98
98
  name: mocha
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ! '>='
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ! '>='
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  description: Meducation's SDK
@@ -125,6 +125,7 @@ files:
125
125
  - Rakefile
126
126
  - lib/meducation_sdk.rb
127
127
  - lib/meducation_sdk/configuration.rb
128
+ - lib/meducation_sdk/helpers.rb
128
129
  - lib/meducation_sdk/mocker.rb
129
130
  - lib/meducation_sdk/resource.rb
130
131
  - lib/meducation_sdk/resources/author.rb
@@ -176,10 +177,12 @@ files:
176
177
  - lib/meducation_sdk/resources/user_email_data.rb
177
178
  - lib/meducation_sdk/resources/user_settings.rb
178
179
  - lib/meducation_sdk/resources/vote.rb
180
+ - lib/meducation_sdk/services/recommender.rb
179
181
  - lib/meducation_sdk/version.rb
180
182
  - meducation_sdk.gemspec
181
183
  - test/arbitary_test.rb
182
184
  - test/configuration_test.rb
185
+ - test/helpers_test.rb
183
186
  - test/mocker_test.rb
184
187
  - test/resource_test.rb
185
188
  - test/resources/author_test.rb
@@ -231,6 +234,7 @@ files:
231
234
  - test/resources/user_settings_test.rb
232
235
  - test/resources/user_test.rb
233
236
  - test/resources/vote_test.rb
237
+ - test/services/recommender_test.rb
234
238
  - test/test_helper.rb
235
239
  homepage: http://github.com/meducation/meducation_sdk
236
240
  licenses:
@@ -242,23 +246,24 @@ require_paths:
242
246
  - lib
243
247
  required_ruby_version: !ruby/object:Gem::Requirement
244
248
  requirements:
245
- - - '>='
249
+ - - ! '>='
246
250
  - !ruby/object:Gem::Version
247
251
  version: '0'
248
252
  required_rubygems_version: !ruby/object:Gem::Requirement
249
253
  requirements:
250
- - - '>='
254
+ - - ! '>='
251
255
  - !ruby/object:Gem::Version
252
256
  version: '0'
253
257
  requirements: []
254
258
  rubyforge_project:
255
- rubygems_version: 2.2.1
259
+ rubygems_version: 2.1.9
256
260
  signing_key:
257
261
  specification_version: 4
258
262
  summary: The SDK for Meducation
259
263
  test_files:
260
264
  - test/arbitary_test.rb
261
265
  - test/configuration_test.rb
266
+ - test/helpers_test.rb
262
267
  - test/mocker_test.rb
263
268
  - test/resource_test.rb
264
269
  - test/resources/author_test.rb
@@ -310,4 +315,5 @@ test_files:
310
315
  - test/resources/user_settings_test.rb
311
316
  - test/resources/user_test.rb
312
317
  - test/resources/vote_test.rb
318
+ - test/services/recommender_test.rb
313
319
  - test/test_helper.rb