unread 0.3.1 → 0.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22da2f765c42c94461c4bf67560a057ed1f76d8f
4
- data.tar.gz: 3d45b07e1d0fc2a3af20b81a8a8fa0b1ff2bf9de
3
+ metadata.gz: 62f6d5dbe191941fe9f5b358318fefbf93ad0c20
4
+ data.tar.gz: 80e1d361fc919f39f33142283b2dfe8d1d9376a1
5
5
  SHA512:
6
- metadata.gz: c51a5ad38b6a49467f3f3d542e06177c9ea3226cadd1001b66f407bea2f1edf65d7f45bad871184697b526938e62a08905e1e44cb154288eb37a886396d5f53a
7
- data.tar.gz: 53b3e25c4723f78121aa3a1f066a68c91b462cbc3a56f5489ac416ba58cb7bb4ea917bc3c174c4b25a852dee4228c10e90c7c054da2f16ceb73b1e5044e79b1b
6
+ metadata.gz: 8808316873efd20db90cb45b9bbf14e4bc6fb3336f69d3f2480bfe8feaee04a21c39a44672d28c892e6365ceb26440525c36283e27d6508baec32f8e2aa72246
7
+ data.tar.gz: a55db92bee6d0b5969cb244655137e08afc7438a8abedbcb65f92a44d05c77ce60dad18d677e64c745b3b831063e08a5076773d717773d30a1685f74d2735f1e
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ coverage/*
@@ -2,8 +2,11 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
+ - 2.1.1
5
6
  gemfile:
6
7
  - ci/Gemfile-rails-3-0
7
8
  - ci/Gemfile-rails-3-1
8
9
  - ci/Gemfile-rails-3-2
9
10
  - ci/Gemfile-rails-4-0
11
+ - ci/Gemfile-rails-4-1
12
+ before_install: gem update bundler
@@ -1,4 +1,6 @@
1
- Copyright (c) 2010,2013 Georg Ledermann
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2010-2014 Georg Ledermann
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -5,6 +5,8 @@ Ruby gem to manage read/unread status of ActiveRecord objects - and it's fast.
5
5
 
6
6
  [![Build Status](https://travis-ci.org/ledermann/unread.png?branch=master)](https://travis-ci.org/ledermann/unread)
7
7
  [![Code Climate](https://codeclimate.com/github/ledermann/unread.png)](https://codeclimate.com/github/ledermann/unread)
8
+ [![Coverage Status](https://coveralls.io/repos/ledermann/unread/badge.png)](https://coveralls.io/r/ledermann/unread)
9
+
8
10
 
9
11
  ## Features
10
12
 
@@ -18,11 +20,16 @@ Ruby gem to manage read/unread status of ActiveRecord objects - and it's fast.
18
20
 
19
21
  ## Requirements
20
22
 
21
- * Ruby 1.9.3 or 2.0.0
23
+ * Ruby 1.9.3 or newer
22
24
  * Rails 3 (including 3.0, 3.1, 3.2) and Rails 4. For use with Rails 2.3 there is a branch named "rails2"
23
25
  * Needs a timestamp field in your models (like created_at or updated_at) with a database index on it
24
26
 
25
27
 
28
+ ## Changelog
29
+
30
+ https://github.com/ledermann/unread/releases
31
+
32
+
26
33
  ## Installation
27
34
 
28
35
  Step 1: Add this to your Gemfile:
@@ -133,4 +140,4 @@ There are two other gems/plugins doing a similar job:
133
140
  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.
134
141
 
135
142
 
136
- Copyright (c) 2010-2013 [Georg Ledermann](http://www.georg-ledermann.de), released under the MIT license
143
+ Copyright (c) 2010-2014 [Georg Ledermann](http://www.georg-ledermann.de), released under the MIT license
data/Rakefile CHANGED
@@ -1,15 +1,6 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
2
3
 
3
- require 'rake'
4
- require 'rake/testtask'
4
+ RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- desc 'Default: run unit tests.'
7
- task :default => :test
8
-
9
- desc 'Test the unread plugin.'
10
- Rake::TestTask.new(:test) do |t|
11
- t.libs << 'lib'
12
- t.libs << 'test'
13
- t.pattern = 'test/**/*_test.rb'
14
- t.verbose = true
15
- end
6
+ task :default => :spec
@@ -1,6 +1,9 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'activerecord', '~> 3.0.10'
3
+ gem 'activerecord', '~> 3.0.20'
4
4
  gem 'sqlite3'
5
5
  gem 'timecop'
6
6
  gem 'rake'
7
+ gem 'rspec'
8
+ gem 'simplecov'
9
+ gem 'coveralls'
@@ -1,6 +1,9 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'activerecord', '~> 3.1.1'
3
+ gem 'activerecord', '~> 3.1.12'
4
4
  gem 'sqlite3'
5
5
  gem 'timecop'
6
6
  gem 'rake'
7
+ gem 'rspec'
8
+ gem 'simplecov'
9
+ gem 'coveralls'
@@ -1,6 +1,9 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'activerecord', '~> 3.2.1'
3
+ gem 'activerecord', '~> 3.2.17'
4
4
  gem 'sqlite3'
5
5
  gem 'timecop'
6
6
  gem 'rake'
7
+ gem 'rspec'
8
+ gem 'simplecov'
9
+ gem 'coveralls'
@@ -1,6 +1,9 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'activerecord', '4.0.0.rc1'
3
+ gem 'activerecord', '~> 4.0.4'
4
4
  gem 'sqlite3'
5
5
  gem 'timecop'
6
6
  gem 'rake'
7
+ gem 'rspec'
8
+ gem 'simplecov'
9
+ gem 'coveralls'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord', '~> 4.1.0'
4
+ gem 'sqlite3'
5
+ gem 'timecop'
6
+ gem 'rake'
7
+ gem 'rspec'
8
+ gem 'simplecov'
9
+ gem 'coveralls'
@@ -9,7 +9,7 @@ module Unread
9
9
  source_root File.expand_path('../templates', __FILE__)
10
10
 
11
11
  def create_migration_file
12
- migration_template 'migration.rb', 'db/migrate/unread_migration'
12
+ migration_template 'migration.rb', 'db/migrate/unread_migration.rb'
13
13
  end
14
14
 
15
15
  def self.next_migration_number(dirname)
@@ -2,6 +2,8 @@ module Unread
2
2
  module Readable
3
3
  module ClassMethods
4
4
  def mark_as_read!(target, options)
5
+ raise ArgumentError unless options.is_a?(Hash)
6
+
5
7
  user = options[:for]
6
8
  assert_reader(user)
7
9
 
@@ -70,7 +72,7 @@ module Unread
70
72
  ReadMark.transaction do
71
73
  ReadMark.delete_all :readable_type => self.base_class.name
72
74
  ReadMark.connection.execute <<-EOT
73
- INSERT INTO read_marks (user_id, readable_type, timestamp)
75
+ INSERT INTO #{ReadMark.table_name} (user_id, readable_type, timestamp)
74
76
  SELECT #{ReadMark.reader_class.primary_key}, '#{self.base_class.name}', '#{Time.current.to_s(:db)}'
75
77
  FROM #{ReadMark.reader_class.table_name}
76
78
  EOT
@@ -4,7 +4,7 @@ module Unread
4
4
  def join_read_marks(user)
5
5
  assert_reader(user)
6
6
 
7
- joins "LEFT JOIN read_marks ON read_marks.readable_type = '#{base_class.name}'
7
+ joins "LEFT JOIN #{ReadMark.table_name} as read_marks ON read_marks.readable_type = '#{base_class.name}'
8
8
  AND read_marks.readable_id = #{table_name}.#{primary_key}
9
9
  AND read_marks.user_id = #{user.id}
10
10
  AND read_marks.timestamp >= #{table_name}.#{readable_options[:on]}"
@@ -1,3 +1,3 @@
1
1
  module Unread
2
- VERSION = '0.3.1'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Unread::Base do
4
+ before :each do
5
+ @email = Email.create!
6
+ wait
7
+ @reader = Reader.create! :name => 'John'
8
+ end
9
+
10
+ describe :acts_as_reader do
11
+ it "should create global read mark" do
12
+ expect(@reader.read_marks.count).to eq 1
13
+ expect(@reader.read_marks.global.count).to eq 1
14
+ end
15
+
16
+ it "should define association for ReadMark" do
17
+ expect(@reader.read_marks.first.user).to eq(@reader)
18
+ end
19
+
20
+ it "should reset read_marks for created reader" do
21
+ expect(Email.unread_by(@reader)).to be_empty
22
+ end
23
+ end
24
+
25
+ describe :acts_as_readable do
26
+ it "should define association" do
27
+ expect(@email.read_marks.count).to eq 0
28
+ end
29
+
30
+ it "should add class to ReadMark.readable_classes" do
31
+ expect(ReadMark.readable_classes).to eq [ Email ]
32
+ end
33
+
34
+ it "should use default options" do
35
+ expect(Email.readable_options).to eq({ :on => :updated_at })
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,4 @@
1
+ class Email < ActiveRecord::Base
2
+ self.primary_key = 'messageid'
3
+ acts_as_readable :on => :updated_at
4
+ end
@@ -0,0 +1,4 @@
1
+ class Reader < ActiveRecord::Base
2
+ self.primary_key = 'number'
3
+ acts_as_reader
4
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReadMark do
4
+ it "should have reader_class" do
5
+ expect(ReadMark.reader_class).to eq Reader
6
+ end
7
+ end
@@ -0,0 +1,206 @@
1
+ require 'spec_helper'
2
+
3
+ describe Unread::Readable do
4
+ before :each do
5
+ @reader = Reader.create! :name => 'David'
6
+ @other_reader = Reader.create :name => 'Matz'
7
+ wait
8
+ @email1 = Email.create!
9
+ wait
10
+ @email2 = Email.create!
11
+ end
12
+
13
+ describe :unread_by do
14
+ it "should return all objects" do
15
+ expect(Email.unread_by(@reader)).to eq [@email1, @email2]
16
+ expect(Email.unread_by(@other_reader)).to eq [@email1, @email2]
17
+ end
18
+
19
+ it "should return unread records" do
20
+ @email1.mark_as_read! :for => @reader
21
+
22
+ expect(Email.unread_by(@reader)).to eq [@email2]
23
+ expect(Email.unread_by(@reader).count).to eq 1
24
+ end
25
+
26
+ it "should not allow invalid parameter" do
27
+ [ 42, nil, 'foo', :foo, {} ].each do |not_a_reader|
28
+ expect {
29
+ Email.unread_by(not_a_reader)
30
+ }.to raise_error(ArgumentError)
31
+ end
32
+ end
33
+
34
+ it "should not allow unsaved reader" do
35
+ unsaved_reader = Reader.new
36
+
37
+ expect {
38
+ Email.unread_by(unsaved_reader)
39
+ }.to raise_error(ArgumentError)
40
+ end
41
+ end
42
+
43
+ describe :with_read_marks_for do
44
+ it "should return readables" do
45
+ expect(Email.with_read_marks_for(@reader).to_a).to eq([@email1, @email2])
46
+ end
47
+
48
+ it "should be countable" do
49
+ expect(Email.with_read_marks_for(@reader).count(:messageid)).to eq(2)
50
+ end
51
+
52
+ it "should not allow invalid parameter" do
53
+ [ 42, nil, 'foo', :foo, {} ].each do |not_a_reader|
54
+ expect {
55
+ Email.with_read_marks_for(not_a_reader)
56
+ }.to raise_error(ArgumentError)
57
+ end
58
+ end
59
+
60
+ it "should not allow unsaved reader" do
61
+ unsaved_reader = Reader.new
62
+
63
+ expect {
64
+ Email.with_read_marks_for(unsaved_reader)
65
+ }.to raise_error(ArgumentError)
66
+ end
67
+ end
68
+
69
+ describe :unread? do
70
+ it "should recognize unread object" do
71
+ expect(@email1.unread?(@reader)).to be_truthy
72
+ expect(@email1.unread?(@other_reader)).to be_truthy
73
+ end
74
+
75
+ it "should handle updating object" do
76
+ @email1.mark_as_read! :for => @reader
77
+ wait
78
+ expect(@email1.unread?(@reader)).to be_falsey
79
+
80
+ @email1.update_attributes! :subject => 'changed'
81
+ expect(@email1.unread?(@reader)).to be_truthy
82
+ end
83
+
84
+ it "should raise error for invalid argument" do
85
+ expect {
86
+ @email1.unread?(42)
87
+ }.to raise_error(ArgumentError)
88
+ end
89
+
90
+ it "should work with eager-loaded read marks" do
91
+ @email1.mark_as_read! :for => @reader
92
+
93
+ expect {
94
+ emails = Email.with_read_marks_for(@reader).to_a
95
+
96
+ expect(emails[0].unread?(@reader)).to be_falsey
97
+ expect(emails[1].unread?(@reader)).to be_truthy
98
+ }.to perform_queries(1)
99
+ end
100
+ end
101
+
102
+ describe '#mark_as_read!' do
103
+ it "should mark a single object as read" do
104
+ @email1.mark_as_read! :for => @reader
105
+
106
+ expect(@email1.unread?(@reader)).to be_falsey
107
+ expect(Email.unread_by(@reader)).to eq [@email2]
108
+
109
+ expect(@email1.unread?(@other_reader)).to be_truthy
110
+ expect(Email.unread_by(@other_reader)).to eq [@email1, @email2]
111
+
112
+ expect(@reader.read_marks.single.count).to eq 1
113
+ expect(@reader.read_marks.single.first.readable).to eq @email1
114
+ end
115
+
116
+ it "should be idempotent" do
117
+ @email1.mark_as_read! :for => @reader
118
+ @email1.mark_as_read! :for => @reader
119
+
120
+ expect(@reader.read_marks.single.count).to eq 1
121
+ end
122
+ end
123
+
124
+ describe '.mark_as_read!' do
125
+ it "should mark multi objects as read" do
126
+ expect(@email1.unread?(@reader)).to be_truthy
127
+ expect(@email2.unread?(@reader)).to be_truthy
128
+
129
+ Email.mark_as_read! [ @email1, @email2 ], :for => @reader
130
+
131
+ expect(@email1.unread?(@reader)).to be_falsey
132
+ expect(@email2.unread?(@reader)).to be_falsey
133
+ end
134
+
135
+ it "should mark all objects as read" do
136
+ Email.mark_as_read! :all, :for => @reader
137
+
138
+ expect(@reader.read_mark_global(Email).timestamp).to eq Time.current
139
+ expect(@reader.read_marks.single).to eq []
140
+ expect(ReadMark.single.count).to eq 0
141
+ expect(ReadMark.global.count).to eq 2
142
+ end
143
+
144
+ it "should mark all objects as read with existing read objects" do
145
+ wait
146
+
147
+ Email.mark_as_read! :all, :for => @reader
148
+ @email1.mark_as_read! :for => @reader
149
+
150
+ expect(@reader.read_marks.single).to eq []
151
+ end
152
+
153
+ it "should not allow invalid arguments" do
154
+ expect {
155
+ Email.mark_as_read! :foo, :for => @reader
156
+ }.to raise_error(ArgumentError)
157
+
158
+ expect {
159
+ Email.mark_as_read! :foo, :bar
160
+ }.to raise_error(ArgumentError)
161
+ end
162
+ end
163
+
164
+ describe :reset_read_marks_for_all do
165
+ it "should reset read marks" do
166
+ Email.reset_read_marks_for_all
167
+
168
+ expect(ReadMark.single.count).to eq 0
169
+ expect(ReadMark.global.count).to eq 2
170
+ end
171
+ end
172
+
173
+ describe :cleanup_read_marks! do
174
+ it "should delete all single read marks" do
175
+ expect(@reader.read_marks.single.count).to eq 0
176
+
177
+ @email1.mark_as_read! :for => @reader
178
+
179
+ expect(Email.unread_by(@reader)).to eq [@email2]
180
+ expect(@reader.read_marks.single.count).to eq 1
181
+
182
+ Email.cleanup_read_marks!
183
+
184
+ @reader.reload
185
+ expect(@reader.read_marks.single.count).to eq 0
186
+ end
187
+
188
+ it "should reset if all objects are read" do
189
+ @email1.mark_as_read! :for => @reader
190
+ @email2.mark_as_read! :for => @reader
191
+
192
+ expect(@reader.read_marks.single.count).to eq 2
193
+
194
+ Email.cleanup_read_marks!
195
+
196
+ expect(@reader.read_marks.single.count).to eq 0
197
+ end
198
+
199
+ it "should not delete read marks from other readables" do
200
+ other_read_mark = @reader.read_marks.create! :readable_type => 'Foo', :readable_id => 42, :timestamp => 5.years.ago
201
+ Email.cleanup_read_marks!
202
+
203
+ expect(ReadMark.exists?(other_read_mark.id)).to be_truthy
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,78 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start do
9
+ add_filter '/spec/'
10
+ end
11
+
12
+ require 'active_record'
13
+ require 'timecop'
14
+ require 'unread'
15
+
16
+ require 'model/reader'
17
+ require 'model/email'
18
+
19
+ # Requires supporting ruby files with custom matchers and macros, etc,
20
+ # in spec/support/ and its subdirectories.
21
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
22
+
23
+ # This file was generated by the `rspec --init` command. Conventionally, all
24
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
25
+ # Require this file using `require "spec_helper"` to ensure that it is only
26
+ # loaded once.
27
+ #
28
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
29
+ RSpec.configure do |config|
30
+ # Run specs in random order to surface order dependencies. If you find an
31
+ # order dependency and want to debug it, you can fix the order by providing
32
+ # the seed, which is printed after each run.
33
+ # --seed 1234
34
+ # config.order = 'random'
35
+
36
+ config.before :each do
37
+ clear_db
38
+ end
39
+
40
+ config.after :each do
41
+ Timecop.return
42
+ end
43
+ end
44
+
45
+ if I18n.respond_to?(:enforce_available_locales=)
46
+ I18n.enforce_available_locales = false
47
+ end
48
+
49
+ def setup_db
50
+ puts "Testing with ActiveRecord #{ActiveRecord::VERSION::STRING}"
51
+
52
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
53
+ ActiveRecord::Migration.verbose = false
54
+
55
+ require File.expand_path('../../lib/generators/unread/migration/templates/migration.rb', __FILE__)
56
+ UnreadMigration.migrate(:up)
57
+
58
+ ActiveRecord::Schema.define(:version => 1) do
59
+ create_table :readers, :primary_key => 'number', :force => true do |t|
60
+ t.string :name
61
+ end
62
+
63
+ create_table :emails, :primary_key => 'messageid', :force => true do |t|
64
+ t.string :subject
65
+ t.text :content
66
+ t.datetime :created_at
67
+ t.datetime :updated_at
68
+ end
69
+ end
70
+ end
71
+
72
+ def clear_db
73
+ Reader.delete_all
74
+ Email.delete_all
75
+ ReadMark.delete_all
76
+ end
77
+
78
+ setup_db
@@ -0,0 +1,22 @@
1
+ RSpec::Matchers.define :perform_queries do |expected|
2
+ match do |block|
3
+ query_count(&block) == expected
4
+ end
5
+
6
+ failure_message do |actual|
7
+ "Expected to run #{expected} queries, got #{@counter.query_count}"
8
+ end
9
+
10
+ def query_count(&block)
11
+ @counter = ActiveRecord::QueryCounter.new
12
+ ActiveSupport::Notifications.subscribe('sql.active_record', @counter.to_proc)
13
+ yield
14
+ ActiveSupport::Notifications.unsubscribe(@counter.to_proc)
15
+
16
+ @counter.query_count
17
+ end
18
+
19
+ def supports_block_expectations?
20
+ true
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ class QueryCounter
3
+ attr_reader :query_count
4
+
5
+ def initialize
6
+ @query_count = 0
7
+ end
8
+
9
+ def to_proc
10
+ lambda(&method(:callback))
11
+ end
12
+
13
+ def callback(name, start, finish, message_id, values)
14
+ @query_count += 1 unless %w(CACHE SCHEMA).include?(values[:name]) || values[:sql] =~ /^begin/i || values[:sql] =~ /^commit/i
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ def wait
2
+ Timecop.freeze(1.minute.from_now.change(:usec => 0))
3
+ end
@@ -23,4 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency 'rake'
24
24
  s.add_development_dependency 'timecop'
25
25
  s.add_development_dependency 'sqlite3'
26
+ s.add_development_dependency 'rspec'
27
+ s.add_development_dependency 'simplecov'
28
+ s.add_development_dependency 'coveralls'
26
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unread
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georg Ledermann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-04 00:00:00.000000000 Z
11
+ date: 2014-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -66,6 +66,48 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: coveralls
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  description: 'This gem creates a scope for unread objects and adds methods to mark
70
112
  objects as read '
71
113
  email:
@@ -80,11 +122,11 @@ files:
80
122
  - MIT-LICENSE
81
123
  - README.md
82
124
  - Rakefile
83
- - changelog.md
84
125
  - ci/Gemfile-rails-3-0
85
126
  - ci/Gemfile-rails-3-1
86
127
  - ci/Gemfile-rails-3-2
87
128
  - ci/Gemfile-rails-4-0
129
+ - ci/Gemfile-rails-4-1
88
130
  - lib/generators/unread/migration/migration_generator.rb
89
131
  - lib/generators/unread/migration/templates/migration.rb
90
132
  - lib/unread.rb
@@ -94,10 +136,15 @@ files:
94
136
  - lib/unread/reader.rb
95
137
  - lib/unread/scopes.rb
96
138
  - lib/unread/version.rb
97
- - test/database.yml
98
- - test/schema.rb
99
- - test/test_helper.rb
100
- - test/unread_test.rb
139
+ - spec/base_spec.rb
140
+ - spec/model/email.rb
141
+ - spec/model/reader.rb
142
+ - spec/read_mark_spec.rb
143
+ - spec/readable_spec.rb
144
+ - spec/spec_helper.rb
145
+ - spec/support/matchers/perform_queries.rb
146
+ - spec/support/query_counter.rb
147
+ - spec/support/timecop.rb
101
148
  - unread.gemspec
102
149
  homepage: ''
103
150
  licenses: []
@@ -118,12 +165,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
165
  version: '0'
119
166
  requirements: []
120
167
  rubyforge_project: unread
121
- rubygems_version: 2.0.14
168
+ rubygems_version: 2.2.2
122
169
  signing_key:
123
170
  specification_version: 4
124
171
  summary: Manages read/unread status of ActiveRecord objects
125
172
  test_files:
126
- - test/database.yml
127
- - test/schema.rb
128
- - test/test_helper.rb
129
- - test/unread_test.rb
173
+ - spec/base_spec.rb
174
+ - spec/model/email.rb
175
+ - spec/model/reader.rb
176
+ - spec/read_mark_spec.rb
177
+ - spec/readable_spec.rb
178
+ - spec/spec_helper.rb
179
+ - spec/support/matchers/perform_queries.rb
180
+ - spec/support/query_counter.rb
181
+ - spec/support/timecop.rb
@@ -1,75 +0,0 @@
1
- # Changelog
2
-
3
- ## 0.3.1 - 2013-12-04
4
-
5
- * Use Time.current instead of Time.now to avoid time zone trouble. Issue #18 (thanks to @henrythe9th)
6
- * Handle primary keys other than "id". Issue #29 (thanks to @bcavileer)
7
-
8
-
9
- ## 0.3.0 - 2013-03-17
10
-
11
- * Support for Rails 4 (beta1)
12
-
13
-
14
- ## 0.2.0 - 2013-02-18
15
-
16
- * Support for Rails 2 dropped
17
- * Refactoring
18
- * Added migration generator
19
-
20
-
21
- ## 0.1.2 - 2013-01-27
22
-
23
- * Scopes: Improved parameter check
24
-
25
-
26
- ## 0.1.1 - 2012-05-01
27
-
28
- * Fixed handling namespaced classes. Closes #10 (thanks to @stanislaw)
29
-
30
-
31
- ## 0.1.0 - 2012-04-21
32
-
33
- * Added scope "with_read_marks_for"
34
- * Fixed #7: Added attr_accessible to all ReadMark attributes (thanks to @negative)
35
-
36
-
37
- ## 0.0.7 - 2012-02-29
38
-
39
- * Cleanup files
40
- * acts_as_reader: Using inverse_of (available since Rails 2.3.6)
41
-
42
-
43
- ## 0.0.6 - 2011-11-11
44
-
45
- * Fixed #5: Gemspec dependency fix (thanks to @bricker88)
46
- * Fixed #6: Removed hard coded dependency on a class named "User" (thanks to @mixandgo)
47
- * Some cleanup
48
-
49
-
50
- ## 0.0.5 - 2011-09-09
51
-
52
- * Fixed class loading issue in development environment
53
-
54
-
55
- ## 0.0.4 - 2011-08-31
56
-
57
- * Ignore multiple calls of acts_as_*
58
- * Improved error messages
59
- * Tested with Rails 3.1
60
-
61
-
62
- ## 0.0.3 - 2011-08-01
63
-
64
- * Fixed gemspec by adding development dependencies
65
- * Testing with Travis CI
66
-
67
-
68
- ## 0.0.2 - 2011-06-23
69
-
70
- * Fixed scoping for ActiveRecord 2.x
71
-
72
-
73
- ## 0.0.1 - 2011-06-23
74
-
75
- * Released as Gem
@@ -1,3 +0,0 @@
1
- sqlite:
2
- adapter: sqlite3
3
- database: ":memory:"
@@ -1,20 +0,0 @@
1
- ActiveRecord::Schema.define(:version => 0) do
2
- create_table :readers, :primary_key => 'number', :force => true do |t|
3
- t.string :name
4
- end
5
-
6
- create_table :emails, :primary_key => 'messageid', :force => true do |t|
7
- t.string :subject
8
- t.text :content
9
- t.datetime :created_at
10
- t.datetime :updated_at
11
- end
12
-
13
- create_table :read_marks, :force => true do |t|
14
- t.integer :readable_id
15
- t.integer :user_id, :null => false
16
- t.string :readable_type, :null => false
17
- t.datetime :timestamp
18
- end
19
- add_index :read_marks, [:user_id, :readable_type, :readable_id]
20
- end
@@ -1,27 +0,0 @@
1
- require 'test/unit'
2
- require 'active_support'
3
- require 'active_support/test_case'
4
- require 'active_record'
5
- require 'timecop'
6
-
7
- configs = YAML.load_file(File.dirname(__FILE__) + '/database.yml')
8
- ActiveRecord::Base.configurations = configs
9
-
10
- ActiveRecord::Base.establish_connection('sqlite')
11
- ActiveRecord::Migration.verbose = false
12
- load(File.dirname(__FILE__) + "/schema.rb")
13
-
14
- require 'unread'
15
-
16
- class Reader < ActiveRecord::Base
17
- self.primary_key = 'number'
18
- acts_as_reader
19
- end
20
-
21
- class Email < ActiveRecord::Base
22
- self.primary_key = 'messageid'
23
-
24
- acts_as_readable :on => :updated_at
25
- end
26
-
27
- puts "Testing with ActiveRecord #{ActiveRecord::VERSION::STRING}"
@@ -1,166 +0,0 @@
1
- require 'test_helper'
2
-
3
- class UnreadTest < ActiveSupport::TestCase
4
- def setup
5
- @reader = Reader.create! :name => 'David'
6
- @other_reader = Reader.create :name => 'Matz'
7
- wait
8
- @email1 = Email.create!
9
- wait
10
- @email2 = Email.create!
11
- end
12
-
13
- def teardown
14
- Reader.delete_all
15
- Email.delete_all
16
- ReadMark.delete_all
17
- Timecop.return
18
- end
19
-
20
- def test_schema_has_loaded_correctly
21
- assert_equal [@email1, @email2], Email.all
22
- end
23
-
24
- def test_readable_classes
25
- assert_equal [ Email ], ReadMark.readable_classes
26
- end
27
-
28
- def test_reader_class
29
- assert_equal Reader, ReadMark.reader_class
30
- end
31
-
32
- def test_scope
33
- assert_equal [@email1, @email2], Email.unread_by(@reader)
34
- assert_equal [@email1, @email2], Email.unread_by(@other_reader)
35
-
36
- assert_equal 2, Email.unread_by(@reader).count
37
- assert_equal 2, Email.unread_by(@other_reader).count
38
- end
39
-
40
- def test_with_read_marks_for
41
- @email1.mark_as_read! :for => @reader
42
-
43
- emails = Email.with_read_marks_for(@reader).to_a
44
-
45
- assert emails[0].read_mark_id.present?
46
- assert emails[1].read_mark_id.nil?
47
-
48
- assert_equal false, emails[0].unread?(@reader)
49
- assert_equal true, emails[1].unread?(@reader)
50
- end
51
-
52
- def test_scope_param_check
53
- [ 42, nil, 'foo', :foo, {} ].each do |not_a_reader|
54
- assert_raise(ArgumentError) { Email.unread_by(not_a_reader)}
55
- assert_raise(ArgumentError) { Email.with_read_marks_for(not_a_reader)}
56
- end
57
-
58
- unsaved_reader = Reader.new
59
- assert_raise(ArgumentError) { Email.unread_by(unsaved_reader)}
60
- assert_raise(ArgumentError) { Email.with_read_marks_for(unsaved_reader)}
61
- end
62
-
63
- def test_scope_after_reset
64
- @email1.mark_as_read! :for => @reader
65
-
66
- assert_equal [@email2], Email.unread_by(@reader)
67
- assert_equal 1, Email.unread_by(@reader).count
68
- end
69
-
70
- def test_unread_after_create
71
- assert_equal true, @email1.unread?(@reader)
72
- assert_equal true, @email1.unread?(@other_reader)
73
-
74
- assert_raise(ArgumentError) {
75
- @email1.unread?(42)
76
- }
77
- end
78
-
79
- def test_unread_after_update
80
- @email1.mark_as_read! :for => @reader
81
- wait
82
- @email1.update_attributes! :subject => 'changed'
83
-
84
- assert_equal true, @email1.unread?(@reader)
85
- end
86
-
87
- def test_mark_as_read
88
- @email1.mark_as_read! :for => @reader
89
-
90
- assert_equal false, @email1.unread?(@reader)
91
- assert_equal [@email2], Email.unread_by(@reader)
92
-
93
- assert_equal true, @email1.unread?(@other_reader)
94
- assert_equal [@email1, @email2], Email.unread_by(@other_reader)
95
-
96
- assert_equal 1, @reader.read_marks.single.count
97
- assert_equal @email1, @reader.read_marks.single.first.readable
98
- end
99
-
100
- def test_mark_as_read_multiple
101
- assert_equal true, @email1.unread?(@reader)
102
- assert_equal true, @email2.unread?(@reader)
103
-
104
- Email.mark_as_read! [ @email1, @email2 ], :for => @reader
105
-
106
- assert_equal false, @email1.unread?(@reader)
107
- assert_equal false, @email2.unread?(@reader)
108
- end
109
-
110
- def test_mark_as_read_with_marked_all
111
- wait
112
-
113
- Email.mark_as_read! :all, :for => @reader
114
- @email1.mark_as_read! :for => @reader
115
-
116
- assert_equal [], @reader.read_marks.single
117
- end
118
-
119
- def test_mark_as_read_twice
120
- @email1.mark_as_read! :for => @reader
121
- @email1.mark_as_read! :for => @reader
122
-
123
- assert_equal 1, @reader.read_marks.single.count
124
- end
125
-
126
- def test_mark_all_as_read
127
- Email.mark_as_read! :all, :for => @reader
128
-
129
- assert_equal Time.current, @reader.read_mark_global(Email).timestamp
130
- assert_equal [], @reader.read_marks.single
131
- assert_equal 0, ReadMark.single.count
132
- assert_equal 2, ReadMark.global.count
133
- end
134
-
135
- def test_cleanup_read_marks
136
- assert_equal 0, @reader.read_marks.single.count
137
-
138
- @email1.mark_as_read! :for => @reader
139
-
140
- assert_equal [@email2], Email.unread_by(@reader)
141
- assert_equal 1, @reader.read_marks.single.count
142
-
143
- Email.cleanup_read_marks!
144
-
145
- @reader.reload
146
- assert_equal 0, @reader.read_marks.single.count
147
- end
148
-
149
- def test_cleanup_read_marks_not_delete_from_other_readables
150
- other_read_mark = @reader.read_marks.create! :readable_type => 'Foo', :readable_id => 42, :timestamp => 5.years.ago
151
- Email.cleanup_read_marks!
152
- assert_equal true, !!ReadMark.exists?(other_read_mark.id) # Rails4 does not return true, but count instead.
153
- end
154
-
155
- def test_reset_read_marks_for_all
156
- Email.reset_read_marks_for_all
157
-
158
- assert_equal 0, ReadMark.single.count
159
- assert_equal 2, ReadMark.global.count
160
- end
161
-
162
- private
163
- def wait
164
- Timecop.freeze(1.minute.from_now.change(:usec => 0))
165
- end
166
- end