named_scope_for_time_attr 1.0.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.
@@ -0,0 +1,4 @@
1
+ == 1.0.0 2009-03-02
2
+
3
+ * Initial release
4
+
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ init.rb
7
+ lib/named_scope_for_time_attr.rb
8
+ lib/named_scope_for_time_attr/named_scope_for_time_attr.rb
9
+ script/destroy
10
+ script/generate
11
+ test/test_helper.rb
12
+ test/test_named_scope_for_time_attr.rb
@@ -0,0 +1,4 @@
1
+
2
+ For more information on named_scope_for_time_attr,
3
+ see http://nsfta.rubyforge.org/
4
+
@@ -0,0 +1,73 @@
1
+ = named_scope_for_time_attr
2
+
3
+ All information can be found here: http://nsfta.rubyforge.org/
4
+
5
+ == DESCRIPTION:
6
+
7
+ Provides the ActiveRecord helper method <tt>named_scope_for_time_attr</tt>.
8
+ Given the name of a time attribute of an ActiveRecord model
9
+ (e.g. <tt>created_at</tt> of <tt>Claim</tt>) it defines a correspondent
10
+ named scope for easy access to an arbitrarily time range (scope).
11
+
12
+ == FEATURES/PROBLEMS:
13
+
14
+ * Defines a named scope for the given time attribute
15
+ * Allows easy access to an arbitrarily time range
16
+ * Defines a named scope <tt>order</tt> for easy ordering of the result
17
+
18
+ == SYNOPSIS:
19
+
20
+ Define the named scope <tt>created_at</tt> and <tt>last_modified_on</tt>
21
+ via <tt>named_scope_for_time_attr</tt>:
22
+
23
+ class Claim < ActiveRecord::Base
24
+ named_scope_for_time_attr :created_at, :order => 'created_at DESC'
25
+ named_scope_for_time_attr :last_modified_on, :limit => 10
26
+ ...
27
+ end
28
+
29
+ It is then possible to use the scope method <tt>created_at</tt> and <tt>updated_at</tt>
30
+ as follows:
31
+
32
+ Claim.created_at(2.days.ago)
33
+ Claim.created_at(2.days.ago, 1.days.ago)
34
+ Claim.created_at(:today)
35
+ Claim.created_at(:this_month).order('created_at DESC')
36
+ Claim.created_at(:q1) # quarter one
37
+ Claim.last_modified_on(3.weeks.ago, :limit => 20)
38
+ ...
39
+
40
+ See API doc for class <tt>named_scope_for_time_attr</tt> for examples:
41
+
42
+ == REQUIREMENTS:
43
+
44
+ * ActiveRecord
45
+
46
+ == INSTALL:
47
+
48
+ * sudo gem install named_scope_for_time_attr
49
+
50
+ == LICENSE:
51
+
52
+ (The MIT License)
53
+
54
+ Copyright (c) 2009-* Thomas Baustert
55
+
56
+ Permission is hereby granted, free of charge, to any person obtaining
57
+ a copy of this software and associated documentation files (the
58
+ 'Software'), to deal in the Software without restriction, including
59
+ without limitation the rights to use, copy, modify, merge, publish,
60
+ distribute, sublicense, and/or sell copies of the Software, and to
61
+ permit persons to whom the Software is furnished to do so, subject to
62
+ the following conditions:
63
+
64
+ The above copyright notice and this permission notice shall be
65
+ included in all copies or substantial portions of the Software.
66
+
67
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
68
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
69
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
70
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
71
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
72
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
73
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/named_scope_for_time_attr'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('named_scope_for_time_attr', NamedScopeForTimeAttr::VERSION) do |p|
7
+ p.developer('Thomas Baustert', 'business@thomasbaustert.de')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
10
+ p.rubyforge_name = "nsfta"
11
+ # p.extra_deps = [
12
+ # ['activesupport','>= 2.0.2'],
13
+ # ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
20
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
21
+ p.rsync_args = '-av --delete --ignore-errors'
22
+ end
23
+
24
+ require 'newgem/tasks' # load /tasks/*.rake
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
26
+
27
+ # TODO - want other tests/tasks run by default? Add them to the list
28
+ # task :default => [:spec, :features]
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Diese Datei macht aus dem Gem ein Rails Plugin
2
+ require 'named_scope_for_time_attr'
@@ -0,0 +1,15 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'active_record'
5
+
6
+ module NamedScopeForTimeAttr
7
+ VERSION = '1.0.0'
8
+ end
9
+
10
+ require File.expand_path(File.dirname(__FILE__) + '/named_scope_for_time_attr/named_scope_for_time_attr')
11
+
12
+ # include the method in ActiveRecord::Base so it is available in all models by default
13
+ ActiveRecord::Base.class_eval do
14
+ include NamedScopeForTimeAttr
15
+ end
@@ -0,0 +1,162 @@
1
+ module NamedScopeForTimeAttr #:nodoc:
2
+
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ ##
10
+ # Provides the <tt>ActiveRecord</tt> helper method <tt>named_scope_for_time_attr</tt>.
11
+ # Given the name of a time attribute of an ActiveRecord model
12
+ # (e.g. <tt>created_at</tt> of <tt>Claim</tt>) it defines a correspondent
13
+ # named scope for easy access to an arbitrarily time range (scope).
14
+ #
15
+ # ==== Examples
16
+ #
17
+ # class Claim < ActiveRecord::Base
18
+ # named_scope_for_time_attr :created_at, :order => 'created_at DESC'
19
+ # named_scope_for_time_attr :updated_at
20
+ # named_scope_for_time_attr :last_modified_on, :limit => 10
21
+ # ...
22
+ # end
23
+ #
24
+ # It is then possible to use the scope method <tt>created_at</tt> and <tt>updated_at</tt>
25
+ # as follows:
26
+ #
27
+ # Claim.created_at(2.days.ago)
28
+ # Claim.updated_at(2.days.ago, 1.days.ago)
29
+ # Claim.last_modified_on(3.weeks.ago)
30
+ #
31
+ # Is is even possible to use one of the following predefined keys to specify a time range:
32
+ #
33
+ # * <tt>:today</tt>
34
+ # * <tt>:yesterday</tt>
35
+ # * <tt>:tomorrow</tt>
36
+ # * <tt>:this_week</tt>
37
+ # * <tt>:last_week</tt>
38
+ # * <tt>:next_week</tt>
39
+ # * <tt>:this_month</tt>
40
+ # * <tt>:last_month</tt>
41
+ # * <tt>:next_month</tt>
42
+ # * <tt>:this_quarter</tt>
43
+ # * <tt>:last_quarter</tt>
44
+ # * <tt>:next_quarter</tt>
45
+ # * <tt>:q1</tt>
46
+ # * <tt>:q2</tt>
47
+ # * <tt>:q3</tt>
48
+ # * <tt>:q4</tt>
49
+ # * <tt>:this_year</tt>
50
+ # * <tt>:last_year</tt>
51
+ # * <tt>:next_year</tt>
52
+ #
53
+ # And use them as follows:
54
+ #
55
+ # Claim.created_at(:today)
56
+ # Claim.updated_at(:this_month)
57
+ # Claim.last_modified_on(:last_year)
58
+ # Claim.created_at(:q1) # quarter one
59
+ # Claim.created_at(:this_quarter)
60
+ #
61
+ # One can specify additional conditional options to <tt>named_scope_for_time_attr</tt>
62
+ # to sort or limit the list of object loaded:
63
+ #
64
+ # class Claim < ActiveRecord::Base
65
+ # named_scope_for_time_attr :created_at, :order => 'created_at DESC'
66
+ # named_scope_for_time_attr :updated_at, :limit => 10
67
+ # ...
68
+ # end
69
+ #
70
+ # The definition also provide a scope <tt>order</tt> to ordered the list which is used
71
+ # as follows:
72
+ #
73
+ # Claim.updated_at(:yesterday).order(:updated_at) # => ... ORDER BY created_at
74
+ # Claim.updated_at(:last_week).order('updated_at DESC') # => ... ORDER BY updated_at DESC
75
+ # Claim.updated_at(:yesterday).order('shortname') # => ... ORDER BY shortname
76
+ #
77
+ def named_scope_for_time_attr(attr_name, options = {})
78
+ named_scope attr_name, lambda { |*args| build_conditions("#{table_name}.#{attr_name}", *args).merge(options) }
79
+ named_scope :order, lambda { |*args| {:order => (args.first || "#{attr_name} DESC") } }
80
+ end
81
+
82
+ private
83
+
84
+ QUARTER_KEYS = [:this_quarter, :last_quarter, :next_quarter, :q1, :q2, :q3, :q4].freeze
85
+ QUARTER_MONTHS = { 1 => [1,3], 2 => [4,6], 3 => [7,9], 4 => [10,12] }.freeze
86
+ MAP_TIME = {
87
+ :today => [ 0, :day],
88
+ :yesterday => [ 1, :day],
89
+ :tomorrow => [-1, :day],
90
+ :this_week => [ 0, :week],
91
+ :last_week => [ 1, :week],
92
+ :next_week => [-1, :week],
93
+ :this_month => [ 0, :month],
94
+ :last_month => [ 1, :month],
95
+ :next_month => [-1, :month],
96
+ :this_year => [ 0, :year],
97
+ :last_year => [ 1, :year],
98
+ :next_year => [-1, :year]
99
+ }
100
+
101
+ ##
102
+ # Examples:
103
+ # build_conditions(:created_at, :last_week)
104
+ # build_conditions(:created_at, 2.days.ago, 1.days.ago)
105
+ # build_conditions(:created_at, 3.hours.ago)
106
+ #
107
+ def build_conditions(attr_name, *args)
108
+ if QUARTER_KEYS.include?(args.first)
109
+ quarter_range_conditions(attr_name, args.first)
110
+ elsif args.first.kind_of?(Symbol)
111
+ count, key = MAP_TIME[args.first]
112
+ time_range_conditions_ago(attr_name, count || 0, key || args.first)
113
+ elsif args.size == 2
114
+ time_range_conditions(attr_name, args.first, args.last)
115
+ else
116
+ {:conditions => ["#{attr_name} >= ?", args.first]}
117
+ end
118
+ end
119
+
120
+ ##
121
+ # Examples:
122
+ # time_range_conditions_ago(:created_at, 0, :day)
123
+ # time_range_conditions_ago(:created_at, 1, :week)
124
+ #
125
+ def time_range_conditions_ago(attr_name, count, key)
126
+ eval("time_range_conditions(attr_name, #{count}.#{key}.ago.beginning_of_#{key}, #{count}.#{key}.ago.end_of_#{key})")
127
+ end
128
+
129
+ def time_range_conditions(attr_name, start_time, end_time)
130
+ {:conditions => ["#{attr_name} >= ? AND #{attr_name} <= ?", start_time, end_time]}
131
+ end
132
+
133
+ def quarter_range_conditions(attr_name, quarter)
134
+ year = Time.now.year
135
+ if quarter.to_s =~ /^q\d{1}/
136
+ quarter = quarter.to_s[1,1].to_i
137
+ else
138
+ month = Time.now.month
139
+ q = #TODO/2009-03-02/tb better code
140
+ if month < 4
141
+ 1
142
+ elsif month < 7
143
+ 2
144
+ elsif month < 10
145
+ 3
146
+ else
147
+ 4
148
+ end
149
+ quarter = q if quarter == :this_quarter
150
+ quarter = q-1 if quarter == :last_quarter
151
+ quarter = q+1 if quarter == :next_quarter
152
+ quarter > 4 ? 1 : (quarter < 1 ? 4 : quarter)
153
+ end
154
+ start_month, end_month = QUARTER_MONTHS[quarter]
155
+ time_range_conditions(attr_name,
156
+ Time.mktime(year, start_month).beginning_of_month,
157
+ Time.mktime(year, end_month).end_of_month)
158
+ end
159
+
160
+ end
161
+ end
162
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,4 @@
1
+ require 'test/unit'
2
+ require 'rubygems' #needed for run tests in TextMate
3
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/named_scope_for_time_attr')
4
+
@@ -0,0 +1,111 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ # The ActiveRecord test model.
4
+ # Note: we don't need a database as long as we only build named scopes.
5
+ class Claim < ActiveRecord::Base
6
+ named_scope_for_time_attr :created_at
7
+ named_scope_for_time_attr :updated_at, :order => 'name DESC'
8
+ end
9
+
10
+ # Simulate a constant time.
11
+ # You can use mocha for this but than you have one dependency more.
12
+ class Time
13
+ def self.now
14
+ Time.mktime(2009,3,1,12,0,0)
15
+ end
16
+ end
17
+
18
+ class TestNamedScopeForTimeAttr < Test::Unit::TestCase
19
+
20
+ # #TODO/2009-03-02/tb
21
+ # tests gehen nicht auf die DB, d.h. das Statement wird nicht wirklich ausgeführt. ist das gut?
22
+
23
+ def test_scope_with_today
24
+ assert_conditions("2009-03-01 00:00:00", "2009-03-01 23:59:59", :today)
25
+ end
26
+
27
+ def test_scope_with_yesterday
28
+ assert_conditions("2009-02-28 00:00:00", "2009-02-28 23:59:59", :yesterday)
29
+ end
30
+
31
+ def test_scope_with_tomorrow
32
+ assert_conditions("2009-03-02 00:00:00", "2009-03-02 23:59:59", :tomorrow)
33
+ end
34
+
35
+ def test_scope_with_this_week
36
+ assert_conditions("2009-02-23 00:00:00", "2009-03-01 23:59:59", :this_week)
37
+ end
38
+
39
+ def test_scope_with_last_week
40
+ assert_conditions("2009-02-16 16 00:00:00", "2009-02-22 23:59:59", :last_week)
41
+ end
42
+
43
+ def test_scope_with_next_week
44
+ assert_conditions("2009-03-02 00:00:00", "2009-03-08 23:59:59", :next_week)
45
+ end
46
+
47
+ def test_scope_with_this_month
48
+ assert_conditions("2009-03-01 00:00:00", "2009-03-31 23:59:59", :this_month)
49
+ end
50
+
51
+ def test_scope_with_last_month
52
+ assert_conditions("2009-02-01 00:00:00", "2009-02-28 23:59:59", :last_month)
53
+ end
54
+
55
+ def test_scope_with_next_month
56
+ assert_conditions("2009-04-01 00:00:00", "2009-04-30 23:59:59", :next_month)
57
+ end
58
+
59
+ def test_scope_with_this_quarter
60
+ assert_conditions("2009-01-01 00:00:00", "2009-03-31 23:59:59", :this_quarter)
61
+ end
62
+
63
+ def test_scope_with_q1
64
+ assert_conditions("2009-01-01 00:00:00", "2009-03-31 23:59:59", :q1)
65
+ end
66
+
67
+ def test_scope_with_q2
68
+ assert_conditions("2009-04-01 00:00:00", "2009-06-30 23:59:59", :q2)
69
+ end
70
+
71
+ def test_scope_with_q3
72
+ assert_conditions("2009-07-01 00:00:00", "2009-09-30 23:59:59", :q3)
73
+ end
74
+
75
+ def test_scope_with_q4
76
+ assert_conditions("2009-10-01 00:00:00", "2009-12-31 23:59:59", :q4)
77
+ end
78
+
79
+ def test_scope_with_this_year
80
+ assert_conditions("2009-01-01 00:00:00", "2009-12-31 23:59:59", :this_year)
81
+ end
82
+
83
+ def test_scope_with_last_year
84
+ assert_conditions("2008-01-01 00:00:00", "2008-12-31 23:59:59", :last_year)
85
+ end
86
+
87
+ def test_scope_with_next_year
88
+ assert_conditions("2010-01-01 00:00:00", "2010-12-31 23:59:59", :next_year)
89
+ end
90
+
91
+ def test_scope_for_created_at_without_order
92
+ assert_nil Claim.created_at(:today).proxy_options[:order]
93
+ end
94
+
95
+ def test_scope_for_updated_at_with_order
96
+ assert_equal "name DESC", Claim.updated_at(:today).proxy_options[:order]
97
+ end
98
+
99
+ private
100
+
101
+ def assert_conditions(start_time, end_time, time_key)
102
+ assert_equal expected_options(start_time, end_time), Claim.created_at(time_key).proxy_options
103
+ end
104
+
105
+ def expected_options(start_time, end_time)
106
+ {:conditions => ["claims.created_at >= ? AND claims.created_at <= ?",
107
+ Time.parse(start_time), Time.parse(end_time)]}
108
+ end
109
+ end
110
+
111
+
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: named_scope_for_time_attr
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Baustert
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-11 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ version:
35
+ description: Provides the ActiveRecord helper method <tt>named_scope_for_time_attr</tt>. Given the name of a time attribute of an ActiveRecord model (e.g. <tt>created_at</tt> of <tt>Claim</tt>) it defines a correspondent named scope for easy access to an arbitrarily time range (scope).
36
+ email:
37
+ - business@thomasbaustert.de
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - PostInstall.txt
46
+ - README.rdoc
47
+ files:
48
+ - History.txt
49
+ - Manifest.txt
50
+ - PostInstall.txt
51
+ - README.rdoc
52
+ - Rakefile
53
+ - init.rb
54
+ - lib/named_scope_for_time_attr.rb
55
+ - lib/named_scope_for_time_attr/named_scope_for_time_attr.rb
56
+ - script/destroy
57
+ - script/generate
58
+ - test/test_helper.rb
59
+ - test/test_named_scope_for_time_attr.rb
60
+ has_rdoc: true
61
+ homepage: "All information can be found here: http://nsfta.rubyforge.org/"
62
+ post_install_message: PostInstall.txt
63
+ rdoc_options:
64
+ - --main
65
+ - README.rdoc
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project: nsfta
83
+ rubygems_version: 1.3.1
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: Provides the ActiveRecord helper method <tt>named_scope_for_time_attr</tt>
87
+ test_files:
88
+ - test/test_helper.rb
89
+ - test/test_named_scope_for_time_attr.rb