unread 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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