directed-edge 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{directed-edge}
8
- s.version = "0.1.3"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Directed Edge"]
12
- s.date = %q{2010-04-09}
12
+ s.date = %q{2010-04-25}
13
13
  s.description = %q{Bindings for the Directed Edge webservices API}
14
14
  s.email = %q{info@directededge.com}
15
15
  s.extra_rdoc_files = [
data/lib/directed_edge.rb CHANGED
@@ -55,6 +55,22 @@ module DirectedEdge
55
55
  end
56
56
  end
57
57
 
58
+ class CollectionHash < Hash
59
+ def initialize(type)
60
+ @type = type
61
+ end
62
+ def [](key)
63
+ self[key] = @type.new unless include? key
64
+ super(key)
65
+ end
66
+ def each
67
+ super { |key, value| yield(key, value) unless value.empty? }
68
+ end
69
+ def empty?
70
+ each { |key, value| return false } ; true
71
+ end
72
+ end
73
+
58
74
  # Base class used for Database and Item that has some basic resource
59
75
  # grabbing functionality.
60
76
 
@@ -92,26 +108,6 @@ module DirectedEdge
92
108
  values
93
109
  end
94
110
 
95
- # Returns a hash of the elements from the document matching the given
96
- # element name. If the specified attribute is present, its value will
97
- # be assigned to the hash, otherwise the default value given will be
98
- # used.
99
-
100
- def hash_from_document(document, element, attribute, default=0)
101
- values = {}
102
- document.elements.each("//#{element}") do |v|
103
- value = v.attribute(attribute).to_s || default
104
- if value.empty?
105
- values[v.text] = default
106
- elsif value.to_i.to_s == value.to_s
107
- values[v.text] = value.to_i
108
- else
109
- values[v.text] = value.to_s
110
- end
111
- end
112
- values
113
- end
114
-
115
111
  # Normalizes the parameters in an argument hash to a standard form
116
112
  # so that they can be passed off to the web services API -- e.g.
117
113
  # :foo_bar to 'fooBar'
@@ -328,13 +324,13 @@ module DirectedEdge
328
324
  @database = database
329
325
 
330
326
  @id = id
331
- @links = {}
327
+ @links = CollectionHash.new(Hash)
332
328
  @tags = Set.new
333
329
  @preselected = []
334
330
  @blacklisted = Set.new
335
331
  @properties = {}
336
332
 
337
- @links_to_remove = Set.new
333
+ @links_to_remove = CollectionHash.new(Set)
338
334
  @tags_to_remove = Set.new
339
335
  @preselected_to_remove = Set.new
340
336
  @blacklisted_to_remove = Set.new
@@ -363,9 +359,13 @@ module DirectedEdge
363
359
 
364
360
  # Creates an item if it does not already exist in the database or overwrites
365
361
  # an existing item if one does.
362
+ #
363
+ # This has been deprecated as it's not set up to properly support link types.
364
+ # use new / save instead.
366
365
 
367
366
  def create(links={}, tags=Set.new, properties={})
368
- @links = links
367
+ warn 'DirectedEdge::Item::create has been deprecated. Use new / save instead.'
368
+ @links[''] = links
369
369
  @tags = tags
370
370
  @properties = properties
371
371
 
@@ -390,6 +390,8 @@ module DirectedEdge
390
390
 
391
391
  put(complete_document, 'add')
392
392
 
393
+ ### CHECKING LINKS_TO_REMOVE.EMPTY? ISN'T CORRECT ANYMORE
394
+
393
395
  if !@links_to_remove.empty? ||
394
396
  !@tags_to_remove.empty? ||
395
397
  !@preselected_to_remove.empty? ||
@@ -410,13 +412,11 @@ module DirectedEdge
410
412
  # will be discarded.
411
413
 
412
414
  def reload
413
- document = read_document
414
-
415
- @links = hash_from_document(document, 'link', 'weight')
416
- @tags = Set.new(list_from_document(document, 'tag'))
417
- @preselected = list_from_document(document, 'preselected')
418
- @blacklisted = Set.new(list_from_document(document, 'blacklisted'))
419
- @properties = {}
415
+ @links.clear
416
+ @tags.clear
417
+ @preselected.clear
418
+ @blacklisted.clear
419
+ @properties.clear
420
420
 
421
421
  @links_to_remove.clear
422
422
  @tags_to_remove.clear
@@ -424,17 +424,15 @@ module DirectedEdge
424
424
  @blacklisted_to_remove.clear
425
425
  @properties_to_remove.clear
426
426
 
427
- document.elements.each('//property') do |element|
428
- @properties[element.attribute('name').value] = element.text
429
- end
430
- @cached = true
427
+ @cached = false
428
+ read
431
429
  end
432
430
 
433
431
  # Returns a set of items that are linked to from this item.
434
432
 
435
- def links
433
+ def links(type='')
436
434
  read
437
- @links
435
+ @links[type.to_s]
438
436
  end
439
437
 
440
438
  # Returns a set containing all of this item's tags.
@@ -515,27 +513,27 @@ module DirectedEdge
515
513
  # item is saved. Otherwise the link will be ignored as the engine tries
516
514
  # to detect 'broken' links that do not terminate at a valid item.
517
515
 
518
- def link_to(other, weight=0)
516
+ def link_to(other, weight=0, type='')
519
517
  raise RangeError if (weight < 0 || weight > 10)
520
- @links_to_remove.delete(other)
521
- @links[other.to_s] = weight
518
+ @links_to_remove[type.to_s].delete(other)
519
+ @links[type.to_s][other.to_s] = weight
522
520
  end
523
521
 
524
522
  # Deletes a link from this item to other.
525
523
  #
526
524
  # The changes will not be reflected in the database until save is called.
527
525
 
528
- def unlink_from(other)
529
- @links_to_remove.add(other.to_s) unless @cached
530
- @links.delete(other.to_s)
526
+ def unlink_from(other, type='')
527
+ @links_to_remove[type.to_s].add(other.to_s) unless @cached
528
+ @links[type.to_s].delete(other.to_s)
531
529
  end
532
530
 
533
531
  # If there is a link for "other" then it returns the weight for the given
534
532
  # item. Zero indicates that no weight is assigned.
535
533
 
536
- def weight_for(other)
534
+ def weight_for(other, type='')
537
535
  read
538
- @links[other.to_s]
536
+ @links[type.to_s][other.to_s]
539
537
  end
540
538
 
541
539
  # Adds a tag to this item.
@@ -639,10 +637,18 @@ module DirectedEdge
639
637
  # already cached.
640
638
 
641
639
  def read
642
- if !@cached
640
+ unless @cached
643
641
  begin
644
642
  document = read_document
645
- @links.merge!(hash_from_document(document, 'link', 'weight'))
643
+
644
+ document.elements.each('//link') do |link_element|
645
+ type = link_element.attribute('type')
646
+ type = type ? type.to_s : ''
647
+ weight = link_element.attribute('weight').to_s.to_i
648
+ target = link_element.text
649
+ @links[type][target] = weight unless @links[type][target]
650
+ end
651
+
646
652
  @tags.merge(list_from_document(document, 'tag'))
647
653
  @preselected.concat(list_from_document(document, 'preselected'))
648
654
  @blacklisted.merge(list_from_document(document, 'blacklisted'))
@@ -652,7 +658,10 @@ module DirectedEdge
652
658
  @properties[name] = element.text unless @properties.has_key?(name)
653
659
  end
654
660
 
655
- @links_to_remove.each { |link| @links.delete(link) }
661
+ @links_to_remove.each do |type, links|
662
+ links.each { |link, weight| @links[type].delete(link) }
663
+ end
664
+
656
665
  @tags_to_remove.each { |tag| @tags.delete(tag) }
657
666
  @preselected_to_remove.each { |p| @preselected.delete(p) }
658
667
  @blacklisted_to_remove.each { |b| @blacklisted.delete(b) }
@@ -665,8 +674,8 @@ module DirectedEdge
665
674
  @properties_to_remove.clear
666
675
 
667
676
  @cached = true
668
- rescue
669
- puts "Couldn't read \"#{@id}\" from the database."
677
+ rescue => ex
678
+ puts "Couldn't read \"#{@id}\" from the database, #{ex}"
670
679
  end
671
680
  end
672
681
  end
@@ -689,7 +698,15 @@ module DirectedEdge
689
698
 
690
699
  def removal_document
691
700
  item = setup_document(REXML::Document.new)
692
- @links_to_remove.each { |link| item.add_element('link').add_text(link.to_s) }
701
+
702
+ @links_to_remove.each do |type, links|
703
+ links.each do |link|
704
+ element = item.add_element('link')
705
+ element.add_attribute(type) unless type.empty?
706
+ element.add_text(link.to_s)
707
+ end
708
+ end
709
+
693
710
  @tags_to_remove.each { |tag| item.add_element('tag').add_text(tag.to_s) }
694
711
  @preselected_to_remove.each { |p| item.add_element('preselected').add_text(p.to_s) }
695
712
  @blacklisted_to_remove.each { |b| item.add_element('blacklisted').add_text(b.to_s) }
@@ -701,10 +718,13 @@ module DirectedEdge
701
718
 
702
719
  def insert_item(document)
703
720
  item = setup_document(document)
704
- @links.each do |link, weight|
705
- element = item.add_element('link')
706
- element.add_attribute('weight', weight.to_s) if weight != 0
707
- element.add_text(link.to_s)
721
+ @links.each do |type, links|
722
+ links.each do |link, weight|
723
+ element = item.add_element('link')
724
+ element.add_attribute('type', type) unless type.empty?
725
+ element.add_attribute('weight', weight.to_s) unless weight == 0
726
+ element.add_text(link.to_s)
727
+ end
708
728
  end
709
729
  @tags.each { |tag| item.add_element('tag').add_text(tag.to_s) }
710
730
  @preselected.each { |p| item.add_element('preselected').add_text(p.to_s) }
@@ -1,4 +1,5 @@
1
1
  require 'helper'
2
+ require 'pp'
2
3
 
3
4
  # Defines a multithreaded "each"
4
5
 
@@ -85,13 +86,17 @@ class TestDirectedEdge < Test::Unit::TestCase
85
86
 
86
87
  def test_items
87
88
  first_item = DirectedEdge::Item.new(@database, 'test_1')
88
- first_item.create
89
+ first_item.save
89
90
 
90
91
  second_item = DirectedEdge::Item.new(@database, 'test_2')
91
- second_item.create([first_item])
92
+ second_item.link_to(first_item)
93
+ second_item.save
92
94
 
93
95
  third_item = DirectedEdge::Item.new(@database, 'test_3')
94
- third_item.create([first_item, second_item], 'test_tag')
96
+ third_item.link_to(first_item)
97
+ third_item.link_to(second_item)
98
+ third_item.add_tag('test_tag')
99
+ third_item.save
95
100
 
96
101
  assert_equal('test_1', first_item.name)
97
102
 
@@ -115,8 +120,8 @@ class TestDirectedEdge < Test::Unit::TestCase
115
120
  # Make sure that the third item is linked to both the first and second items
116
121
 
117
122
  assert_equal(2, third_item.links.length)
118
- assert(third_item.links.include?(first_item))
119
- assert(third_item.links.include?(second_item))
123
+ assert(third_item.links.include?(first_item.to_s))
124
+ assert(third_item.links.include?(second_item.to_s))
120
125
 
121
126
  # Make sure that the first and second items show up in the related items for
122
127
  # the third item
@@ -230,13 +235,34 @@ class TestDirectedEdge < Test::Unit::TestCase
230
235
  assert(!item.properties.include?('test_property_1'))
231
236
  end
232
237
 
238
+ def test_link_types
239
+ first = DirectedEdge::Item.new(@database, 'item_1')
240
+ second = DirectedEdge::Item.new(@database, 'item_2')
241
+ first.save
242
+ second.save
243
+
244
+ first.link_to(second, 0, :test)
245
+ first.save
246
+
247
+ first = DirectedEdge::Item.new(@database, 'item_1')
248
+ second = DirectedEdge::Item.new(@database, 'item_2')
249
+
250
+ first.save
251
+ first.reload
252
+ second.reload
253
+
254
+ assert(first.links(:test).include?('item_2'))
255
+ assert(!first.links.include?('item_2'))
256
+ end
257
+
233
258
  def test_load
234
259
  return if ENV['NO_LOAD_TEST']
235
260
 
236
261
  def run_load_test(prefix, count)
237
262
  (1..count).concurrently do |i|
238
263
  item = DirectedEdge::Item.new(@database, "test_item_#{prefix}_#{i}")
239
- item.create([], ['test_tag'])
264
+ item.add_tag('test_tag')
265
+ item.save
240
266
  end
241
267
  (1..count).concurrently do |i|
242
268
  item = DirectedEdge::Item.new(@database, "test_item_#{prefix}_#{i}")
@@ -372,10 +398,10 @@ class TestDirectedEdge < Test::Unit::TestCase
372
398
 
373
399
  def test_blacklisted
374
400
  customer = DirectedEdge::Item.new(@database, 'customer1')
375
- first = customer.recommended.first
401
+ first = customer.recommended(['product']).first
376
402
  customer.add_blacklisted(first)
377
403
  customer.save
378
- assert_not_equal(customer.recommended.first, first)
404
+ assert(!customer.recommended(['product']).include?(first))
379
405
 
380
406
  assert(customer.blacklisted.include?(first))
381
407
  customer.reload
@@ -386,6 +412,6 @@ class TestDirectedEdge < Test::Unit::TestCase
386
412
  assert(!customer.blacklisted.include?(first))
387
413
  customer.reload
388
414
  assert(!customer.blacklisted.include?(first))
389
- assert_equal(customer.recommended.first, first)
415
+ assert(customer.recommended(['product']).include?(first))
390
416
  end
391
417
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 3
9
- version: 0.1.3
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Directed Edge
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-09 00:00:00 +02:00
17
+ date: 2010-04-25 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency