From e03eea710bba422046fb993d0f17ccba6d74629f Mon Sep 17 00:00:00 2001 From: Mauricio Giacomini Girardello <mauriciogiacomini4@gmail.com> Date: Mon, 31 Aug 2015 16:23:14 -0300 Subject: [PATCH] refactoring ranking module decouple rater class from sort alg, create concrete classes for item, rated item and basic rater strategy --- lib/ranking/README.md | 29 +++++++-------- lib/ranking/item.rb | 18 +++++++++ lib/ranking/rank.rb | 53 --------------------------- lib/ranking/rated_item.rb | 10 +++++ lib/ranking/rater.rb | 11 ++++++ lib/ranking/strategies/basic_rater.rb | 26 +++++++++++++ lib/ranking/strategy.rb | 15 ++++++++ 7 files changed, 94 insertions(+), 68 deletions(-) create mode 100644 lib/ranking/item.rb delete mode 100644 lib/ranking/rank.rb create mode 100644 lib/ranking/rated_item.rb create mode 100644 lib/ranking/rater.rb create mode 100644 lib/ranking/strategies/basic_rater.rb create mode 100644 lib/ranking/strategy.rb diff --git a/lib/ranking/README.md b/lib/ranking/README.md index a05757ba7..0f01c85eb 100644 --- a/lib/ranking/README.md +++ b/lib/ranking/README.md @@ -1,19 +1,18 @@ -# Use Example -### Input : - items = [Item.new("ax",1,1,1,["otherStuffA","lala",'a']),Item.new("bx",2,2,2,[1,2,3,"teste","lblb",'b']),Item.new("cx",1,1,99,[3,2,1,"teste","lclc",'c'])] +# Ranking docs + +# Refactored -### Rank call : +```ruby +items = [] +items << Ranking::Item.new("ax",1,1,1,["otherStuffA","lala",'a']) +items << Ranking::Item.new("bx",2,2,2,[1,2,3,"teste","lblb",'b']) +items << Ranking::Item.new("cx",1,1,99,[3,2,1,"teste","lclc",'c']) - Rater.new.sortByRate(items).each { |i| puts i } - -###### OR +rater = Ranking::Rater.new(Ranking::Strategies::BasicRater.new(1000, 1, 100)) +rater.sortByRate(items).each do |i| + p i.name +end +``` - Rater.new( # Order of the arguments is important! - positionWeight = 1000, - useWeight = 1, - likeWeight = 100 - ).sortByRate(items).each { |i| puts i } - - -#### Return (output) : +## Output - ordered array of Items, starting from the most ranked to the least \ No newline at end of file diff --git a/lib/ranking/item.rb b/lib/ranking/item.rb new file mode 100644 index 000000000..33fc5009b --- /dev/null +++ b/lib/ranking/item.rb @@ -0,0 +1,18 @@ +# This class represents an item of ranking +class Ranking::Item + # name = name of object + # views = view count + # downloads = download count + # likes = like count + # info = just for convinience of sorting it together, won't be touched + attr_accessor :name, :views, :downloads, :likes, :info + + def initialize(name, views = 0, downloads = 0, likes = 0, info = nil) + @name = name + @views = views + @downloads = downloads + @likes = likes + @info = info + end + +end \ No newline at end of file diff --git a/lib/ranking/rank.rb b/lib/ranking/rank.rb deleted file mode 100644 index 73698a258..000000000 --- a/lib/ranking/rank.rb +++ /dev/null @@ -1,53 +0,0 @@ -# Input: Array of struct Item (sorted by DB name matching) -# Output: Array of struct Item sorted by ranking - -Item = Struct.new :name,:views,:downloads,:likes,:otherInfo # For interfacing -# name = name of object -# views = view count -# downloads = download count -# likes = like count -# otherInfo = Anything, just for convinience of sorting it together, won't be touched - -class Rater #INTERFACE - def initialize positionWeight = nil, useWeight = nil, likeWeight = nil - @rater = BasicRater.new positionWeight, useWeight, likeWeight - end - def sortByRate items - @rater.sortByRate items - end -end - -class BasicRater # Don't instanciate this directly, use Rater - - RatedItem = Struct.new(:item,:rate) - - def initialize positionWeight = nil, useWeight = nil, likeWeight = nil - @positionWeight = (positionWeight == nil ? 1000 : positionWeight) - @useWeight = (useWeight == nil ? 3 : useWeight) - @likeWeight = (likeWeight == nil ? 100 : likeWeight) - end - - def rateItem item, inversePosition # Returns: RatedItem instance - - positionRating = inversePosition * @positionWeight - useRating = (item.downloads < item.views ? item.downloads : item.views)*@useWeight - likeRating = item.likes * @likeWeight - - rate = positionRating + useRating + likeRating - RatedItem.new( item, rate ) - - end - - def sortByRate items - first = items.first - rest = items.drop(1) - - rest.zip( rest.size.downto(1) ) - .collect { |item,reverseIndex| self.rateItem( item, reverseIndex ) } # Returns RatedItem instance - .sort { |itemA,itemB| itemA.rate <=> itemB.rate } - .collect { |ri| ri.item } - .push( first ) - .reverse # Best ranked comes first - end - -end diff --git a/lib/ranking/rated_item.rb b/lib/ranking/rated_item.rb new file mode 100644 index 000000000..baa5aa8ec --- /dev/null +++ b/lib/ranking/rated_item.rb @@ -0,0 +1,10 @@ +# This class represents an item rated in ranking +# Have an association with a rank item +class Ranking::RatedItem + attr_accessor :item, :rate + + def initialize(item, rate) + @item = item + @rate = rate + end +end \ No newline at end of file diff --git a/lib/ranking/rater.rb b/lib/ranking/rater.rb new file mode 100644 index 000000000..75b3d4018 --- /dev/null +++ b/lib/ranking/rater.rb @@ -0,0 +1,11 @@ +class Ranking::Rater + + def initialize(rater_strategy) + @rater = rater_strategy + end + + def sortByRate(items) + @rater.sortByRate items + end + +end \ No newline at end of file diff --git a/lib/ranking/strategies/basic_rater.rb b/lib/ranking/strategies/basic_rater.rb new file mode 100644 index 000000000..8c03c3d29 --- /dev/null +++ b/lib/ranking/strategies/basic_rater.rb @@ -0,0 +1,26 @@ +class Ranking::Strategies::BasicRater < Ranking::Strategy + + def sortByRate(items) + first = items.first + rest = items.drop(1) + + rest.zip(rest.size.downto(1)) + .collect { |item, reverseIndex| rateItem(item, reverseIndex) } # Returns RatedItem instance + .sort { |itemA, itemB| itemA.rate <=> itemB.rate } + .collect { |ri| ri.item } + .push(first) + .reverse # Best ranked comes first + end + + private + + def rateItem(item, inversePosition) + positionRating = inversePosition * @positionWeight + useRating = (item.downloads < item.views ? item.downloads : item.views) * @useWeight + likeRating = item.likes * @likeWeight + + rate = positionRating + useRating + likeRating + build_rated_item item, rate + end + +end \ No newline at end of file diff --git a/lib/ranking/strategy.rb b/lib/ranking/strategy.rb new file mode 100644 index 000000000..ffce28174 --- /dev/null +++ b/lib/ranking/strategy.rb @@ -0,0 +1,15 @@ +class Ranking::Strategy + + def initialize(positionWeight = nil, useWeight = nil, likeWeight = nil) + @positionWeight = (positionWeight == nil ? 1000 : positionWeight) + @useWeight = (useWeight == nil ? 3 : useWeight) + @likeWeight = (likeWeight == nil ? 100 : likeWeight) + end + + protected + + def build_rated_item(item, rate) + Ranking::RatedItem.new(item, rate) + end + +end \ No newline at end of file -- GitLab