unread 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -18,82 +18,87 @@ Ruby gem to manage read/unread status of ActiveRecord objects - and it's fast.
18
18
 
19
19
  ## Requirements
20
20
 
21
- * Ruby 1.8.7 or 1.9.x
21
+ * Ruby 1.8.7 or 1.9.3
22
22
  * Rails >= 2.3.6 (including 3.0, 3.1, 3.2)
23
23
  * Tested with SQLite and MySQL
24
- * Needs a timestamp field in your models (e.g. created_at) with a database index on it
24
+ * Needs a timestamp field in your models (like created_at or updated_at) with a database index on it
25
25
 
26
26
 
27
27
  ## Installation
28
28
 
29
29
  Step 1: Add this to your Gemfile:
30
-
30
+
31
31
  gem 'unread'
32
-
32
+
33
33
  and run
34
-
34
+
35
35
  bundle
36
-
37
-
36
+
37
+
38
38
  Step 2: Add this migration:
39
-
40
- class CreateReadMarks < ActiveRecord::Migration
41
- def self.up
42
- create_table :read_marks, :force => true do |t|
43
- t.integer :readable_id
44
- t.integer :user_id, :null => false
45
- t.string :readable_type, :null => false, :limit => 20
46
- t.datetime :timestamp
47
- end
48
- add_index :read_marks, [:user_id, :readable_type, :readable_id]
49
- end
50
-
51
- def self.down
52
- drop_table :read_marks
53
- end
39
+
40
+ ```ruby
41
+ class CreateReadMarks < ActiveRecord::Migration
42
+ def self.up
43
+ create_table :read_marks, :force => true do |t|
44
+ t.integer :readable_id
45
+ t.integer :user_id, :null => false
46
+ t.string :readable_type, :null => false, :limit => 20
47
+ t.datetime :timestamp
54
48
  end
55
49
 
50
+ add_index :read_marks, [:user_id, :readable_type, :readable_id]
51
+ end
52
+
53
+ def self.down
54
+ drop_table :read_marks
55
+ end
56
+ end
57
+ ```
58
+
56
59
  and run the migration:
57
-
60
+
58
61
  rake db:migrate
59
62
 
60
63
 
61
64
  ## Usage
62
65
 
63
- class User < ActiveRecord::Base
64
- acts_as_reader
65
- end
66
-
67
- class Message < ActiveRecord::Base
68
- acts_as_readable :on => :created_at
69
- end
66
+ ```ruby
67
+ class User < ActiveRecord::Base
68
+ acts_as_reader
69
+ end
70
+
71
+ class Message < ActiveRecord::Base
72
+ acts_as_readable :on => :created_at
73
+ end
74
+
75
+ message1 = Message.create!
76
+ message2 = Message.create!
77
+
78
+ ## Get unread messages for a given user
79
+ Message.unread_by(current_user)
80
+ # => [ message1, message2 ]
81
+
82
+ message1.mark_as_read! :for => current_user
83
+ Message.unread_by(current_user)
84
+ # => [ message2 ]
70
85
 
71
- message1 = Message.create!
72
- message2 = Message.create!
73
-
74
- ## Get unread messages for a given user
75
- Message.unread_by(current_user)
76
- # => [ message1, message2 ]
77
-
78
- message1.mark_as_read! :for => current_user
79
- Message.unread_by(current_user)
80
- # => [ message2 ]
81
-
82
- ## Get all messages including the read status for a given user
83
- messages = Message.with_read_marks_for(current_user)
84
- # => [ message1, message2 ]
85
- messages[0].unread?(current_user)
86
- # => false
87
- messages[1].unread?(current_user)
88
- # => true
89
-
90
- Message.mark_as_read! :all, :for => current_user
91
- Message.unread_by(current_user)
92
- # => [ ]
93
-
94
- # Optional: Cleaning up unneeded markers
95
- # Do this in a cron job once a day.
96
- Message.cleanup_read_marks!
86
+ ## Get all messages including the read status for a given user
87
+ messages = Message.with_read_marks_for(current_user)
88
+ # => [ message1, message2 ]
89
+ messages[0].unread?(current_user)
90
+ # => false
91
+ messages[1].unread?(current_user)
92
+ # => true
93
+
94
+ Message.mark_as_read! :all, :for => current_user
95
+ Message.unread_by(current_user)
96
+ # => [ ]
97
+
98
+ # Optional: Cleaning up unneeded markers.
99
+ # Do this in a cron job once a day.
100
+ Message.cleanup_read_marks!
101
+ ```
97
102
 
98
103
 
99
104
  ## How does it work?
@@ -109,21 +114,26 @@ It will be ensured that the list of read items will not grow up too much:
109
114
 
110
115
  Overall, this gem can be used for large data. Please have a look at the generated SQL queries, here is an example:
111
116
 
112
- # Assuming we have a user who has marked all messages as read on 2010-10-20 08:50
113
- current_user = User.find(42)
114
-
115
- # Get the unread messages for this user
116
- Message.unread_by(current_user)
117
-
118
- # =>
119
- # SELECT messages.*
120
- # FROM messages
121
- # LEFT JOIN read_marks ON read_marks.readable_type = 'Message'
122
- # AND read_marks.readable_id = messages.id
123
- # AND read_marks.user_id = 42
124
- # AND read_marks.timestamp >= messages.created_at
125
- # WHERE read_marks.id IS NULL
126
- # AND messages.created_at > '2010-10-20 08:50:00'
117
+ ```ruby
118
+ # Assuming we have a user who has marked all messages as read on 2010-10-20 08:50
119
+ current_user = User.find(42)
120
+
121
+ # Get the unread messages for this user
122
+ Message.unread_by(current_user)
123
+ ```
124
+
125
+ Generated query:
126
+
127
+ ```sql
128
+ SELECT messages.*
129
+ FROM messages
130
+ LEFT JOIN read_marks ON read_marks.readable_type = 'Message'
131
+ AND read_marks.readable_id = messages.id
132
+ AND read_marks.user_id = 42
133
+ AND read_marks.timestamp >= messages.created_at
134
+ WHERE read_marks.id IS NULL
135
+ AND messages.created_at > '2010-10-20 08:50:00'
136
+ ```
127
137
 
128
138
  Hint: You should add a database index on `messages.created_at`.
129
139
 
@@ -138,4 +148,4 @@ There are two other gems/plugins doing a similar job:
138
148
  Unfortunately, both of them have a lack of performance, because they calculate the unread records doing a `find(:all)`, which should be avoided for a large amount of records. This gem is based on a timestamp algorithm and therefore it's very fast.
139
149
 
140
150
 
141
- Copyright (c) 2010,2012 [Georg Ledermann](http://www.georg-ledermann.de), released under the MIT license
151
+ Copyright (c) 2010-2013 [Georg Ledermann](http://www.georg-ledermann.de), released under the MIT license
@@ -1,3 +1,7 @@
1
+ 0.1.2 - 2013/01/27
2
+
3
+ * Scopes: Improved parameter check
4
+
1
5
  0.1.1 - 2012/05/01
2
6
 
3
7
  * Fixed handling namespaced classes. Closes #10 (thanks to @stanislaw)
@@ -3,5 +3,5 @@ source :rubygems
3
3
  gem 'activerecord', '~> 2.3.14'
4
4
  gem 'sqlite3'
5
5
  gem 'mysql2', '~> 0.2.11'
6
- gem 'mocha'
6
+ gem 'mocha', "~> 0.12.8"
7
7
  gem 'rake'
@@ -3,5 +3,5 @@ source :rubygems
3
3
  gem 'activerecord', '~> 3.0.10'
4
4
  gem 'sqlite3'
5
5
  gem 'mysql2', '~> 0.2.11'
6
- gem 'mocha'
6
+ gem 'mocha', "~> 0.12.8"
7
7
  gem 'rake'
@@ -3,5 +3,5 @@ source :rubygems
3
3
  gem 'activerecord', '~> 3.1.1'
4
4
  gem 'sqlite3'
5
5
  gem 'mysql2', '>= 0.3.6'
6
- gem 'mocha'
6
+ gem 'mocha', "~> 0.12.8"
7
7
  gem 'rake'
@@ -3,5 +3,5 @@ source :rubygems
3
3
  gem 'activerecord', '~> 3.2.1'
4
4
  gem 'sqlite3'
5
5
  gem 'mysql2', '>= 0.3.6'
6
- gem 'mocha'
6
+ gem 'mocha', "~> 0.12.8"
7
7
  gem 'rake'
@@ -106,7 +106,7 @@ module Unread
106
106
  end
107
107
 
108
108
  def cleanup_read_marks!
109
- assert_reader
109
+ assert_reader_class
110
110
 
111
111
  ReadMark.reader_class.find_each do |user|
112
112
  ReadMark.transaction do
@@ -126,7 +126,7 @@ module Unread
126
126
  end
127
127
 
128
128
  def reset_read_marks!(user = :all)
129
- assert_reader
129
+ assert_reader_class
130
130
 
131
131
  ReadMark.transaction do
132
132
  if user == :all
@@ -145,12 +145,15 @@ module Unread
145
145
  true
146
146
  end
147
147
 
148
- def assert_reader(user=nil)
149
- if ReadMark.reader_class
150
- if user && !user.is_a?(ReadMark.reader_class)
151
- raise ArgumentError, "Class #{user.class.name} is not registered by acts_as_reader!"
152
- end
153
- else
148
+ def assert_reader(user)
149
+ assert_reader_class
150
+
151
+ raise ArgumentError, "Class #{user.class.name} is not registered by acts_as_reader!" unless user.is_a?(ReadMark.reader_class)
152
+ raise ArgumentError, "The given user has no id!" unless user.id
153
+ end
154
+
155
+ def assert_reader_class
156
+ unless ReadMark.reader_class
154
157
  raise RuntimeError, 'There is no class using acts_as_reader!'
155
158
  end
156
159
  end
@@ -1,3 +1,3 @@
1
1
  module Unread
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -12,15 +12,12 @@ ActiveRecord::Base.establish_connection(db_name)
12
12
  ActiveRecord::Migration.verbose = false
13
13
  load(File.dirname(__FILE__) + "/schema.rb")
14
14
 
15
- module App
16
- class Reader < ActiveRecord::Base
17
- acts_as_reader
18
- end
15
+ class Reader < ActiveRecord::Base
16
+ acts_as_reader
17
+ end
19
18
 
20
- class Email < ActiveRecord::Base
21
- acts_as_readable :on => :updated_at
22
- end
19
+ class Email < ActiveRecord::Base
20
+ acts_as_readable :on => :updated_at
23
21
  end
24
- include App
25
22
 
26
23
  puts "Testing with ActiveRecord #{ActiveRecord::VERSION::STRING}"
@@ -34,10 +34,6 @@ class UnreadTest < ActiveSupport::TestCase
34
34
 
35
35
  assert_equal 2, Email.unread_by(@reader).count
36
36
  assert_equal 2, Email.unread_by(@other_reader).count
37
-
38
- assert_raise(ArgumentError) {
39
- Email.unread_by(42)
40
- }
41
37
  end
42
38
 
43
39
  def test_with_read_marks_for
@@ -52,6 +48,17 @@ class UnreadTest < ActiveSupport::TestCase
52
48
  assert_equal true, emails[1].unread?(@reader)
53
49
  end
54
50
 
51
+ def test_scope_param_check
52
+ [ 42, nil, 'foo', :foo, {} ].each do |not_a_reader|
53
+ assert_raise(ArgumentError) { Email.unread_by(not_a_reader)}
54
+ assert_raise(ArgumentError) { Email.with_read_marks_for(not_a_reader)}
55
+ end
56
+
57
+ unsaved_reader = Reader.new
58
+ assert_raise(ArgumentError) { Email.unread_by(unsaved_reader)}
59
+ assert_raise(ArgumentError) { Email.with_read_marks_for(unsaved_reader)}
60
+ end
61
+
55
62
  def test_scope_after_reset
56
63
  @email1.mark_as_read! :for => @reader
57
64
 
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.add_dependency 'activerecord', '>= 2.3.6'
22
22
 
23
23
  s.add_development_dependency 'rake'
24
- s.add_development_dependency 'mocha'
24
+ s.add_development_dependency 'mocha', "~> 0.12.8"
25
25
  s.add_development_dependency 'sqlite3'
26
26
  s.add_development_dependency 'mysql2'
27
27
  end
metadata CHANGED
@@ -1,104 +1,104 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: unread
3
- version: !ruby/object:Gem::Version
4
- hash: 25
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
5
+ version: 0.1.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Georg Ledermann
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-05-01 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: activerecord
12
+ date: 2013-01-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 15
29
- segments:
30
- - 2
31
- - 3
32
- - 6
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
33
20
  version: 2.3.6
21
+ none: false
34
22
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
23
+ name: activerecord
24
+ requirement: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: 2.3.6
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ prerelease: false
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ none: false
38
+ type: :development
37
39
  name: rake
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ none: false
46
+ - !ruby/object:Gem::Dependency
38
47
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ~>
51
+ - !ruby/object:Gem::Version
52
+ version: 0.12.8
40
53
  none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 0
47
- version: "0"
48
54
  type: :development
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
55
  name: mocha
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 0.12.8
61
+ none: false
62
+ - !ruby/object:Gem::Dependency
52
63
  prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
54
69
  none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: 3
59
- segments:
60
- - 0
61
- version: "0"
62
70
  type: :development
63
- version_requirements: *id003
64
- - !ruby/object:Gem::Dependency
65
71
  name: sqlite3
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ none: false
78
+ - !ruby/object:Gem::Dependency
66
79
  prerelease: false
67
- requirement: &id004 !ruby/object:Gem::Requirement
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
68
85
  none: false
69
- requirements:
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- hash: 3
73
- segments:
74
- - 0
75
- version: "0"
76
86
  type: :development
77
- version_requirements: *id004
78
- - !ruby/object:Gem::Dependency
79
87
  name: mysql2
80
- prerelease: false
81
- requirement: &id005 !ruby/object:Gem::Requirement
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
82
93
  none: false
83
- requirements:
84
- - - ">="
85
- - !ruby/object:Gem::Version
86
- hash: 3
87
- segments:
88
- - 0
89
- version: "0"
90
- type: :development
91
- version_requirements: *id005
92
- description: "This gem creates a scope for unread objects and adds methods to mark objects as read "
93
- email:
94
+ description: ! 'This gem creates a scope for unread objects and adds methods to mark
95
+ objects as read '
96
+ email:
94
97
  - mail@georg-ledermann.de
95
98
  executables: []
96
-
97
99
  extensions: []
98
-
99
100
  extra_rdoc_files: []
100
-
101
- files:
101
+ files:
102
102
  - .gitignore
103
103
  - .travis.yml
104
104
  - Gemfile
@@ -119,40 +119,31 @@ files:
119
119
  - test/test_helper.rb
120
120
  - test/unread_test.rb
121
121
  - unread.gemspec
122
- homepage: ""
122
+ homepage: ''
123
123
  licenses: []
124
-
125
124
  post_install_message:
126
125
  rdoc_options: []
127
-
128
- require_paths:
126
+ require_paths:
129
127
  - lib
130
- required_ruby_version: !ruby/object:Gem::Requirement
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
131
133
  none: false
132
- requirements:
133
- - - ">="
134
- - !ruby/object:Gem::Version
135
- hash: 3
136
- segments:
137
- - 0
138
- version: "0"
139
- required_rubygems_version: !ruby/object:Gem::Requirement
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
140
139
  none: false
141
- requirements:
142
- - - ">="
143
- - !ruby/object:Gem::Version
144
- hash: 3
145
- segments:
146
- - 0
147
- version: "0"
148
140
  requirements: []
149
-
150
141
  rubyforge_project: unread
151
- rubygems_version: 1.8.24
142
+ rubygems_version: 1.8.25
152
143
  signing_key:
153
144
  specification_version: 3
154
145
  summary: Manages read/unread status of ActiveRecord objects
155
- test_files:
146
+ test_files:
156
147
  - test/database.yml
157
148
  - test/schema.rb
158
149
  - test/test_helper.rb