boole_time 0.1.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +86 -0
- data/Rakefile +2 -0
- data/boole_time.gemspec +24 -0
- data/lib/boole_time.rb +76 -0
- data/lib/boole_time/railtie.rb +9 -0
- data/lib/boole_time/version.rb +3 -0
- data/spec/boole_time_spec.rb +106 -0
- data/spec/spec_helper.rb +29 -0
- metadata +125 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Pete Browne
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# BooleTime
|
2
|
+
|
3
|
+
ActiveRecord plugin for creating a boolean virtual attribute and scopes from
|
4
|
+
a date or datetime column.
|
5
|
+
|
6
|
+
## Getting Started
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
# Gemfile
|
10
|
+
gem 'boole_time'
|
11
|
+
```
|
12
|
+
|
13
|
+
```bash
|
14
|
+
$ bundle install
|
15
|
+
$ rails generate model Post published_at:datetime
|
16
|
+
# Or any model with a datetime column
|
17
|
+
```
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# app/models/post.rb
|
21
|
+
class Post < ActiveRecord::Base
|
22
|
+
boole_time :published_at
|
23
|
+
end
|
24
|
+
|
25
|
+
# elsewhere
|
26
|
+
post = Post.new
|
27
|
+
post.published = true
|
28
|
+
post.published_at
|
29
|
+
# => (Time.now)
|
30
|
+
post.published = false
|
31
|
+
post.published_at
|
32
|
+
# => nil
|
33
|
+
```
|
34
|
+
|
35
|
+
## Documentation
|
36
|
+
|
37
|
+
BooleTime considers a datetime attribute truthy if it is in the past.
|
38
|
+
If the attribute is nil or in the future, it is considered false:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
post = Post.new
|
42
|
+
post.published
|
43
|
+
# => false
|
44
|
+
post.published_at = 2.weeks.ago
|
45
|
+
post.published
|
46
|
+
# => true
|
47
|
+
post.published_at = 2.weeks.from_now
|
48
|
+
post.published
|
49
|
+
# => false
|
50
|
+
# Time travel to 3 weeks from now...
|
51
|
+
post.published
|
52
|
+
# => true
|
53
|
+
```
|
54
|
+
|
55
|
+
### Other Methods
|
56
|
+
|
57
|
+
BooleTime also adds some query methods along with a negative version of the virtual attribute:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
post.published
|
61
|
+
# => false
|
62
|
+
post.published?
|
63
|
+
# => false
|
64
|
+
post.unpublished
|
65
|
+
# => true
|
66
|
+
post.unpublished?
|
67
|
+
# => true
|
68
|
+
```
|
69
|
+
|
70
|
+
### Scopes
|
71
|
+
|
72
|
+
BooleTime automatically adds named scopes that correspond to the positive and negative versions of the virtual attribute:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
Post.create published_at: nil
|
76
|
+
Post.create published_at: 2.weeks.ago
|
77
|
+
Post.create published_at: 2.weeks.from_now
|
78
|
+
Post.published
|
79
|
+
# => [#<Post id: 2, published_at: "(2 weeks ago)">]
|
80
|
+
Post.unpublished
|
81
|
+
# => [#<Post id: 1, published_at: nil>, #<Post id: 3, published_at: "(2 weeks from now)">]
|
82
|
+
```
|
83
|
+
|
84
|
+
## Copyright
|
85
|
+
|
86
|
+
Copyright (c) 2012 [Pete Browne](http://petebrowne.com). See LICENSE for details.
|
data/Rakefile
ADDED
data/boole_time.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/boole_time/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['Pete Browne']
|
6
|
+
gem.email = ['me@petebrowne.com']
|
7
|
+
gem.description = %q{ActiveRecord plugin for creating a boolean virtual attribute from
|
8
|
+
a datetime column.}
|
9
|
+
gem.summary = %q{ActiveRecord plugin for creating a boolean virtual attribute and scopes from
|
10
|
+
a date or datetime column.}
|
11
|
+
gem.homepage = 'http://github.com/petebrowne/boole_time'
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.name = 'boole_time'
|
17
|
+
gem.require_paths = ['lib']
|
18
|
+
gem.version = BooleTime::VERSION
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rspec', '~> 2.11'
|
21
|
+
gem.add_development_dependency 'timecop', '~> 0.4'
|
22
|
+
gem.add_development_dependency 'activerecord', '~> 3.2'
|
23
|
+
gem.add_development_dependency 'sqlite3', '~> 1.3'
|
24
|
+
end
|
data/lib/boole_time.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'boole_time/version'
|
2
|
+
|
3
|
+
module BooleTime
|
4
|
+
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].freeze
|
5
|
+
|
6
|
+
# Creates a boolean attribute that corresponds to a date or date_time
|
7
|
+
# attribute. For instance:
|
8
|
+
#
|
9
|
+
# class Post < ActiveRecord::Base
|
10
|
+
# boole_time :published_at
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Generates these methods:
|
14
|
+
#
|
15
|
+
# post.published = true
|
16
|
+
# # sets published_at to Time.now
|
17
|
+
# post.published
|
18
|
+
# # => true
|
19
|
+
# post.published = false
|
20
|
+
# # sets published_at to nil
|
21
|
+
# post.published?
|
22
|
+
# # => false
|
23
|
+
#
|
24
|
+
def boole_time(*fields)
|
25
|
+
options = fields.extract_options!
|
26
|
+
mixin = generated_feature_methods
|
27
|
+
|
28
|
+
fields.each do |field|
|
29
|
+
name = options[:name] || field.to_s.sub(/_(at|on)\z/, '')
|
30
|
+
negative = options[:negative] || "un#{name}"
|
31
|
+
true_scope = options[:true_scope] || name
|
32
|
+
false_scope = options[:false_scope] || negative
|
33
|
+
|
34
|
+
unless options[:scopes] == false
|
35
|
+
# Define truthy scope
|
36
|
+
scope(true_scope, Proc.new {
|
37
|
+
where(arel_table[field].lt(Time.now))
|
38
|
+
}) unless options[:true_scope] == false
|
39
|
+
|
40
|
+
# Define falsy scope
|
41
|
+
scope(false_scope, Proc.new {
|
42
|
+
field_attr = arel_table[field]
|
43
|
+
where(field_attr.eq(nil).or(field_attr.gt(Time.now)))
|
44
|
+
}) unless options[:false_scope] == false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Define writer method
|
48
|
+
mixin.redefine_method(:"#{name}=") do |value|
|
49
|
+
if TRUE_VALUES.include?(value)
|
50
|
+
__send__(:"#{field}=", Time.now) unless __send__(name)
|
51
|
+
else
|
52
|
+
__send__(:"#{field}=", nil) if __send__(name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Define reader and query methods
|
57
|
+
mixin.redefine_method(name) do
|
58
|
+
value = __send__(field)
|
59
|
+
value.present? && value < Time.now
|
60
|
+
end
|
61
|
+
mixin.redefine_method(:"#{name}?") { __send__(name) }
|
62
|
+
|
63
|
+
# Define negative reader and query methods
|
64
|
+
unless options[:negative] == false
|
65
|
+
mixin.redefine_method(negative) { !__send__(name) }
|
66
|
+
mixin.redefine_method(:"#{negative}?") { !__send__(name) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if defined?(ActiveRecord)
|
73
|
+
ActiveRecord::Base.extend BooleTime
|
74
|
+
elsif defined?(Rails)
|
75
|
+
require 'boole_time/railtie'
|
76
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BooleTime do
|
4
|
+
context 'when the time is nil' do
|
5
|
+
subject(:post) { Post.new published_at: nil }
|
6
|
+
|
7
|
+
its(:published) { should be_false }
|
8
|
+
its(:published?) { should be_false }
|
9
|
+
its(:unpublished) { should be_true }
|
10
|
+
its(:unpublished?) { should be_true }
|
11
|
+
|
12
|
+
context 'when set to true' do
|
13
|
+
before { post.published = true }
|
14
|
+
its(:published_at) { should eq(Time.now) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when set to false' do
|
18
|
+
before { post.published = false }
|
19
|
+
its(:published_at) { should be_nil }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when the time is in the future' do
|
24
|
+
subject(:post) { Post.new published_at: 2.weeks.from_now }
|
25
|
+
|
26
|
+
its(:published) { should be_false }
|
27
|
+
its(:published?) { should be_false }
|
28
|
+
its(:unpublished) { should be_true }
|
29
|
+
its(:unpublished?) { should be_true }
|
30
|
+
|
31
|
+
context 'when set to true' do
|
32
|
+
before { post.published = true }
|
33
|
+
its(:published_at) { should eq(Time.now) }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when set to false' do
|
37
|
+
before { post.published = false }
|
38
|
+
its(:published_at) { should eq(2.weeks.from_now) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when the time is in the past' do
|
43
|
+
subject(:post) { Post.new published_at: 2.weeks.ago }
|
44
|
+
|
45
|
+
its(:published) { should be_true }
|
46
|
+
its(:published?) { should be_true }
|
47
|
+
its(:unpublished) { should be_false }
|
48
|
+
its(:unpublished?) { should be_false }
|
49
|
+
|
50
|
+
context 'when set to true' do
|
51
|
+
before { post.published = true }
|
52
|
+
its(:published_at) { should eq(2.weeks.ago) }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when set to false' do
|
56
|
+
before { post.published = false }
|
57
|
+
its(:published_at) { should be_nil }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with various times' do
|
62
|
+
subject { Post }
|
63
|
+
|
64
|
+
before do
|
65
|
+
@post_1 = Post.create published_at: nil
|
66
|
+
@post_2 = Post.create published_at: 2.weeks.ago
|
67
|
+
@post_3 = Post.create published_at: 2.weeks.from_now
|
68
|
+
end
|
69
|
+
|
70
|
+
after { Post.delete_all }
|
71
|
+
|
72
|
+
its(:published) { should match_array([@post_2]) }
|
73
|
+
its(:unpublished) { should match_array([@post_1, @post_3]) }
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'without scopes' do
|
77
|
+
subject { Post }
|
78
|
+
it { should_not respond_to(:subscribed) }
|
79
|
+
it { should_not respond_to(:unsubscribed) }
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'without negatives' do
|
83
|
+
subject { Post.new }
|
84
|
+
it { should_not respond_to(:unsubscribed) }
|
85
|
+
it { should_not respond_to(:unsubscribed?) }
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'with a custom name' do
|
89
|
+
subject { Post.new }
|
90
|
+
it { should respond_to(:trashed=) }
|
91
|
+
it { should respond_to(:trashed) }
|
92
|
+
it { should respond_to(:trashed?) }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with a custom negative name' do
|
96
|
+
subject { Post.new }
|
97
|
+
it { should respond_to(:treasured) }
|
98
|
+
it { should respond_to(:treasured?) }
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with custom scope names' do
|
102
|
+
subject { Post }
|
103
|
+
it { should respond_to(:with_comments_open) }
|
104
|
+
it { should respond_to(:with_comments_closed) }
|
105
|
+
end
|
106
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'active_record'
|
4
|
+
require 'boole_time'
|
5
|
+
require 'timecop'
|
6
|
+
|
7
|
+
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
|
8
|
+
ActiveRecord::Migration.verbose = false
|
9
|
+
ActiveRecord::Schema.define(:version => 1) do
|
10
|
+
create_table :posts do |t|
|
11
|
+
t.datetime :published_at
|
12
|
+
t.datetime :deleted_at
|
13
|
+
t.date :subscribed_on
|
14
|
+
t.date :comments_closed_on
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Post < ActiveRecord::Base
|
19
|
+
boole_time :published_at
|
20
|
+
boole_time :deleted_at, name: 'trashed', negative: 'treasured'
|
21
|
+
boole_time :subscribed_on, scopes: false, negative: false
|
22
|
+
boole_time :comments_closed_on, true_scope: 'with_comments_closed', false_scope: 'with_comments_open'
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec.configure do |config|
|
26
|
+
config.before(:all) do
|
27
|
+
Timecop.freeze
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: boole_time
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pete Browne
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.11'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.11'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: timecop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0.4'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.4'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activerecord
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.2'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sqlite3
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.3'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.3'
|
78
|
+
description: ! 'ActiveRecord plugin for creating a boolean virtual attribute from
|
79
|
+
|
80
|
+
a datetime column.'
|
81
|
+
email:
|
82
|
+
- me@petebrowne.com
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- Gemfile
|
89
|
+
- LICENSE
|
90
|
+
- README.md
|
91
|
+
- Rakefile
|
92
|
+
- boole_time.gemspec
|
93
|
+
- lib/boole_time.rb
|
94
|
+
- lib/boole_time/railtie.rb
|
95
|
+
- lib/boole_time/version.rb
|
96
|
+
- spec/boole_time_spec.rb
|
97
|
+
- spec/spec_helper.rb
|
98
|
+
homepage: http://github.com/petebrowne/boole_time
|
99
|
+
licenses: []
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.8.23
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: ActiveRecord plugin for creating a boolean virtual attribute and scopes from
|
122
|
+
a date or datetime column.
|
123
|
+
test_files:
|
124
|
+
- spec/boole_time_spec.rb
|
125
|
+
- spec/spec_helper.rb
|