acts_as_daterange 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6b73444d2249e280d38d31b6f85adf1125c1b143
4
+ data.tar.gz: ef339bf722d67ad32a4820b44ccbe1d0f1d17b4c
5
+ SHA512:
6
+ metadata.gz: 39c486c508d7e92a1339c7925b0bffc703a8a5cf327cda755a505c410568d89bb17e4fed5663d7ce98336f8dc8972b8e7e31de9db92cff65edec8d9ca2b94aaa
7
+ data.tar.gz: 6a9e429b000b308b8f9d84673d3c8497cfcf00db59a9bc3710eace1127003ddc1d4c4964f7f9a92d04d810bf70728b0c22aaabfcba7259f36793836bd9c8aeb1
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in acts_as_daterange.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Gilad Zohari
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,78 @@
1
+ # ActsAsDaterange
2
+
3
+ This is home to the acts_as_daterange GEM.
4
+ It adds the 'acts_as_daterange' directive to ActiveRecord models, and adds methods, scopes and validations
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'acts_as_daterange'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install acts_as_daterange
19
+
20
+ ## Usage
21
+
22
+ Given an AR model, for example Coupon, with start_date and end_date fields:
23
+ ```ruby
24
+ class Coupon < ActiveRecord::Base
25
+ attr_accessible :start_date, :end_date
26
+ acts_as_daterange
27
+ end
28
+
29
+ > @coupon = Coupon.create start_date: 3.hours.ago, end_date: 3.hours.from_now
30
+ ```
31
+
32
+ methods:
33
+ ```ruby
34
+ > @coupon.active_now?
35
+ > @coupon.started?
36
+ > @coupon.ended?
37
+ ```
38
+
39
+ scopes:
40
+ ```ruby
41
+ > Coupon.active_now
42
+ > Coupon.inactive_now
43
+ > Coupon.active_at Date.today
44
+ > Coupon.inactive_at 5.hours.ago
45
+ ```
46
+
47
+ validations:
48
+ ```ruby
49
+ > @coupon = Coupon.create start_date: 3.hours.from_now, end_date: 3.hours.ago
50
+ > @coupon.errors[:end_date]
51
+ => must be after start_date
52
+ ```
53
+
54
+ Notice that:
55
+ - start_date=nil means started? == true always
56
+ - and end_date=nil means that ended? == false always
57
+
58
+ ```ruby
59
+ > Coupon.new.started?
60
+ => true
61
+ > Coupon.new.ended?
62
+ => false
63
+ ```
64
+
65
+ You can also override the field names:
66
+ ```ruby
67
+ acts_as_daterange :started_at, :ended_at
68
+ # or
69
+ acts_as_daterange start_date: :started_at, end_date: :ended_at
70
+ ```
71
+
72
+ ## Contributing
73
+
74
+ 1. Fork it
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
77
+ 4. Push to the branch (`git push origin my-new-feature`)
78
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'acts_as_daterange/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "acts_as_daterange"
8
+ spec.version = ActsAsDaterange::VERSION
9
+ spec.authors = ["Gilad Zohari"]
10
+ spec.email = [""]
11
+ spec.description = %q{adds daterange to AR models}
12
+ spec.summary = %q{adds daterange to AR models}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency 'activerecord', '>= 3.0'
22
+ spec.add_runtime_dependency 'activesupport', '>= 3.0'
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency 'sqlite3'
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,78 @@
1
+ module Daterange
2
+ extend ActiveSupport::Concern
3
+ included do
4
+ class_attribute :daterange_config
5
+ validate :daterange_period
6
+ end
7
+
8
+ module ClassMethods
9
+ def expire_column
10
+ daterange_config[:expire_column]
11
+ end
12
+
13
+ def start_column
14
+ daterange_config[:start_column]
15
+ end
16
+
17
+ def active_at(time)
18
+ where("(#{start_column} IS NULL OR #{start_column} <= :time) AND
19
+ (#{expire_column} IS NULL OR #{expire_column} > :time)",
20
+ time: time)
21
+ end
22
+
23
+ def inactive_at(time)
24
+ where("#{start_column} > :time OR #{expire_column} < :time",
25
+ time: time)
26
+ end
27
+
28
+ def active_now
29
+ active_at(Time.now)
30
+ end
31
+
32
+ def inactive_now
33
+ inactive_at(Time.now)
34
+ end
35
+ end
36
+
37
+ def expire_column
38
+ self.class.expire_column
39
+ end
40
+
41
+ def start_column
42
+ self.class.start_column
43
+ end
44
+
45
+ def expire
46
+ write_attribute(start_column, nil)
47
+ write_attribute(expire_column, Time.now)
48
+ end
49
+
50
+ def expire!
51
+ update_attribute(start_column, nil)
52
+ update_attribute(expire_column, Time.now)
53
+ end
54
+
55
+ def active_now?
56
+ started? and not ended?
57
+ end
58
+
59
+ private
60
+
61
+ def daterange_period
62
+ errors[start_column] << "must be present" if !self[start_column]
63
+ errors[expire_column] << "be present" if !self[expire_column]
64
+ if self[expire_column] < self[start_column]
65
+ errors[expire_column] << "must be after #{start_column}"
66
+ end
67
+ end
68
+
69
+ def started?
70
+ start_col = read_attribute(start_column)
71
+ start_col.nil? || start_col < Time.now
72
+ end
73
+
74
+ def ended?
75
+ expire_col = read_attribute(expire_column)
76
+ expire_col && expire_col < Time.now
77
+ end
78
+ end
@@ -0,0 +1,3 @@
1
+ module ActsAsDaterange
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,38 @@
1
+ require "acts_as_daterange/version"
2
+ require 'active_record'
3
+ require 'active_support/concern'
4
+ require 'acts_as_daterange/daterange'
5
+
6
+ class ActiveRecord::Base
7
+ extend ActsAsDaterange
8
+ end
9
+
10
+ module ActsAsDaterange
11
+ # use default start_date, end_date
12
+ # acts_as_daterange
13
+
14
+ # set your own custom start_date and end_date
15
+ # acts_as_daterange :started_at, :ended_at
16
+ # or
17
+ # acts_as_daterange start_date: :started_at, end_date: :ended_at
18
+ def acts_as_expirable(*args, start_date: nil, end_date: nil)
19
+ include Daterange
20
+
21
+ if args.present?
22
+ if start_date || end_date || args.count != 2
23
+ raise ArgumentError.new("ActsAsDaterange: must have both start_date and end_date")
24
+ end
25
+ start_column,expire_column = args
26
+ elsif start_date || end_date
27
+ if !start_date || !end_date
28
+ raise ArgumentError.new("ActsAsDaterange: must have both start_date and end_date")
29
+ end
30
+ start_column,expire_column = start_date, end_date
31
+ end
32
+
33
+ self.daterange_config = {
34
+ start_column: start_column || 'start_date',
35
+ expire_column: expire_column || 'end_date'
36
+ }
37
+ end
38
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+ describe Daterange do
3
+ before do
4
+ setup
5
+ end
6
+
7
+ describe 'default daterange' do
8
+ it 'validates daterange' do
9
+ expect { TestDefaultDaterange.create!(title: "That Time-Turner, it was driving me mad. I've handed it in", start_date: Time.now + 2.day, end_date: Time.now + 1.days) }.to raise_error(ActiveRecord::RecordInvalid)
10
+ end
11
+
12
+ describe '.expire' do
13
+ let(:record) { TestDefaultDaterange.create!(title: 'right now!', start_date: Time.now - 100.day, end_date: Time.now + 100.days) }
14
+ it "expires record" do
15
+ expect(record).to be_active_now
16
+ record.expire
17
+ expect(record).to_not be_active_now
18
+ end
19
+
20
+ it "doesn't commit the update" do
21
+ expect(record).to be_active_now
22
+ record.expire
23
+ record.reload
24
+ expect(record).to be_active_now
25
+ end
26
+ end
27
+ describe '.expire!' do
28
+ let(:record) { TestDefaultDaterange.create!(title: 'right now!', start_date: Time.now - 100.day, end_date: Time.now + 100.days) }
29
+ it "commits the expiration" do
30
+ expect(record).to be_active_now
31
+ record.expire!
32
+ expect(record).to_not be_active_now
33
+ record.reload
34
+ expect(record).to_not be_active_now
35
+ end
36
+ end
37
+
38
+ context "future daterange" do
39
+ before do
40
+ TestDefaultDaterange.create!(title: 'future', start_date: Time.now + 1.day, end_date: Time.now + 2.days)
41
+ end
42
+ let(:future_daterange) { TestDefaultDaterange.first }
43
+ it "isn't .active_now?" do
44
+ expect(future_daterange).to_not be_active_now
45
+ end
46
+ it "is #inactive_now" do
47
+ expect(TestDefaultDaterange.inactive_now.count).to eq 1
48
+ end
49
+ it "isn't #active_now" do
50
+ expect(TestDefaultDaterange.active_now).to be_empty
51
+ end
52
+ it "isn't #inactive_at tomorrow" do
53
+ expect(TestDefaultDaterange.inactive_at(Time.now + 1.day)).to be_empty
54
+ end
55
+ it "is #active_at tomorrow" do
56
+ expect(TestDefaultDaterange.active_at(Time.now + 1.day).count).to eq 1
57
+ end
58
+ end
59
+
60
+ context "active daterange" do
61
+ before do
62
+ TestDefaultDaterange.create!(title: 'right now!', start_date: Time.now - 100.day, end_date: Time.now + 100.days)
63
+ end
64
+ let(:active_daterange) { TestDefaultDaterange.first }
65
+ it "is .active_now?" do
66
+ expect(active_daterange).to be_active_now
67
+ end
68
+ it "is #active_now" do
69
+ expect(TestDefaultDaterange.active_now.count).to eq 1
70
+ end
71
+ it "isn't #inactive_now" do
72
+ expect(TestDefaultDaterange.inactive_now).to be_empty
73
+ end
74
+ it "is #inactive_at tomorrow" do
75
+ expect(TestDefaultDaterange.inactive_at(Time.now + 200.day).count).to eq 1
76
+ end
77
+ it "isn't #active_at tomorrow" do
78
+ expect(TestDefaultDaterange.active_at(Time.now + 200.day)).to be_empty
79
+ end
80
+ end
81
+
82
+ context "expired daterange" do
83
+ before do
84
+ TestDefaultDaterange.create!(title: 'old news buddy!', start_date: Time.now - 100.day, end_date: Time.now - 99.days)
85
+ end
86
+ it "is #inactive_now" do
87
+ expect(TestDefaultDaterange.inactive_now.count).to eq 1
88
+ end
89
+ it "isn't #active_now" do
90
+ expect(TestDefaultDaterange.active_now).to be_empty
91
+ end
92
+ end
93
+ end
94
+
95
+ describe 'custom daterange' do
96
+ it 'has active items' do
97
+ TestCustomDaterange.create!(title: "i'm special me", promotion_start: Time.now - 2.day, promotion_expire: Time.now + 9.days)
98
+ expect(TestCustomDaterange.active_now.count).to eq 1
99
+ expect(TestCustomDaterange.inactive_now.count).to eq 0
100
+ end
101
+ it 'has inactive items' do
102
+ TestCustomDaterange.create!(title: "i'm special me", promotion_start: Time.now - 12.day, promotion_expire: Time.now - 9.days)
103
+ expect(TestCustomDaterange.active_now.count).to eq 0
104
+ expect(TestCustomDaterange.inactive_now.count).to eq 1
105
+ end
106
+ it 'validates daterange' do
107
+ expect { TestCustomDaterange.create!(title: "That Time-Turner, it was driving me mad. I've handed it in", promotion_start: Time.now + 2.day, promotion_expire: Time.now + 1.days) }.to raise_error(ActiveRecord::RecordInvalid)
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+
114
+
@@ -0,0 +1,48 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'acts_as_daterange'
8
+ require 'acts_as_daterange/daterange'
9
+ RSpec.configure do |config|
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+
14
+ # Run specs in random order to surface order dependencies. If you find an
15
+ # order dependency and want to debug it, you can fix the order by providing
16
+ # the seed, which is printed after each run.
17
+ # --seed 1234
18
+ config.order = 'random'
19
+ end
20
+
21
+ def setup
22
+ ActiveRecord::Base.establish_connection(
23
+ :adapter => 'sqlite3',
24
+ :database => ':memory:'
25
+ )
26
+
27
+ ActiveRecord::Schema.define do
28
+ create_table :test_default_dateranges, force: true do |t|
29
+ t.column :title, :string
30
+ t.column :start_date, :datetime
31
+ t.column :end_date, :datetime
32
+ end
33
+
34
+ create_table :test_custom_dateranges, force: true do |t|
35
+ t.column :title, :string
36
+ t.column :promotion_start, :datetime
37
+ t.column :promotion_expire, :datetime
38
+ end
39
+ end
40
+ end
41
+
42
+ class TestDefaultDaterange < ActiveRecord::Base
43
+ acts_as_expirable
44
+ end
45
+
46
+ class TestCustomDaterange < ActiveRecord::Base
47
+ acts_as_expirable :promotion_start, :promotion_expire
48
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_daterange
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gilad Zohari
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
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: rspec
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
+ description: adds daterange to AR models
98
+ email:
99
+ - ''
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - .rspec
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - acts_as_daterange.gemspec
111
+ - lib/acts_as_daterange.rb
112
+ - lib/acts_as_daterange/daterange.rb
113
+ - lib/acts_as_daterange/version.rb
114
+ - spec/daterange_spec.rb
115
+ - spec/spec_helper.rb
116
+ homepage: ''
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.0.8
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: adds daterange to AR models
140
+ test_files:
141
+ - spec/daterange_spec.rb
142
+ - spec/spec_helper.rb