public
Last active — forked from antirez/gist:924301

  • Download Gist
gistfile1.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
require 'rubygems'
require 'json'
require 'redis'
 
class RedisComments
def initialize(redis,namespace,sort_proc=nil)
@r = redis
@namespace = namespace
@sort_proc = sort_proc
end
 
def thread_key(thread_id)
"thread:#{@namespace}:#{thread_id}"
end
 
def insert(thread_id,comment)
raise "no parent_id field" if !comment.has_key?('parent_id')
key = thread_key(thread_id)
id = @r.hincrby(key,:nextid,1)
@r.hset(key,id,comment.to_json)
return id.to_i
end
 
def edit(thread_id,comment_id,comment)
key = thread_key(thread_id)
old = @r.hget(key,id)
return false if !old
comment['parent_id'] = JSON.parse(old)['parent_id']
@r.hset(key,id,comment.to_json)
return true
end
 
 
def remove_thread(thread_id)
@r.del(thread_key(thread_id))
end
 
def comments_in_thread(thread_id)
@r.hlen(thread_key(thread_id)).to_i-1
end
 
def del_comment(thread_id,comment_id)
# TODO? You may want to make sure there are no parents.
# If there are parents we can call edit() with "comment removed"
# or something like that.
#
# A probably wiser implementation is to *never* use this method
# and instead flag the comment as deleted. Then when rendering we
# can display it in a special way if there ara replies, otherwise
# we can avoid displaying deleted comments that are leafs.
@r.hdel(thread_key(thread_id),comment_id)
end
 
def render_comments(thread_id,&block)
byparent = {}
@r.hgetall(thread_key(thread_id)).each{|id,comment|
next if id == "nextid"
c = JSON.parse(comment)
c['id'] = id.to_i
parent_id = c['parent_id'].to_i
byparent[parent_id] = [] if !byparent.has_key?(parent_id)
byparent[parent_id] << c
}
 
render_comments_rec(byparent,-1,0,block)
end
 
def render_comments_rec(byparent,parent_id,level,block)
thislevel = byparent[parent_id]
thislevel = @sort_proc.call(thislevel,level) if @sort_proc
thislevel.each{|c|
c['level'] = level
block.call(c)
if byparent[c['id']]
render_comments_rec(byparent,c['id'],level+1,block)
end
}
end
end
 
# In this example we want comments at top level sorted in reversed chronological
# order, but all the sub trees sorted in plain chronological order.
comments = RedisComments.new(Redis.new,"mycomments",proc{|c,level|
if level == 0
c.sort {|a,b| b['ctime'] <=> a['ctime']}
else
c.sort {|a,b| a['ctime'] <=> b['ctime']}
end
})
 
comments.remove_thread(50)
first_id = comments.insert(50,
{'body' => 'First comment at top level','parent_id'=>-1,'ctime'=>1000}
)
 
second_id = comments.insert(50,
{'body' => 'Second comment at top level','parent_id'=>-1,'ctime'=>1001}
)
id = comments.insert(50,
{'body' => 'reply number one','parent_id'=>second_id,'ctime'=>1002}
)
id = comments.insert(50,
{'body' => 'reply to reply','parent_id'=>id,'ctime'=>1003}
)
id = comments.insert(50,
{'body' => 'reply number two','parent_id'=>second_id,'ctime'=>1002}
)
rendered_comments = comments.render_comments(50) {|c|
puts (" "*c['level']) + c['body']
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.