season 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 899d9f7e0405d00eb51394bcb984c496ed0b06fc
4
- data.tar.gz: 91138329eec2efd1ee082eb6e30dc284a418047f
3
+ metadata.gz: ee585a77f75b912e9967cee60051590a4df64ddb
4
+ data.tar.gz: db1c30b2d54d0bec8f2e36c0b10cfa6b657150b6
5
5
  SHA512:
6
- metadata.gz: af150a59bfa9de34841468175840cd0edfa130c38232dcd934fa04a6321ccc28550d45ca0c680323e3a55b3cc4b062bf8d22d15c8fa703caeaa77861ca2d1fdf
7
- data.tar.gz: 6d83a87905bf1941d0108d245f26e9a17c1a9d9c2fa512ed12b4e45fb0862ebef1c389201d71584c3e5927718331c50974d0d047fdbb0af6a4db389d14e0286a
6
+ metadata.gz: 6f2d10ab32b50dbf017b57ba7ffbf31bcd38186aadd43ec23faa49f32b90279531c648caa9fc21d6e0cc0ac057d1f0faa5c936507f8e24427e3be9d6ca876a8e
7
+ data.tar.gz: 874d00169c9fc23a75f37c57ec75e08aca1b3ffd9881dd6950b9891e65d1f7597246162fca0f948fe16913d998810adbb82c184ed1c8d07d2251a7e0b449a469
data/.gitignore CHANGED
@@ -12,3 +12,5 @@
12
12
  *.o
13
13
  *.a
14
14
  mkmf.log
15
+ *.sublime-project
16
+ *.sublime-workspace
data/README.md CHANGED
@@ -26,7 +26,7 @@ In this first version Season only supports ActiveRecord, but we plan to also sup
26
26
 
27
27
  ## Usage
28
28
 
29
- To use Season scopes just append `_before`, `_after` or `_between` to your datetime column names and pass the arguments accordingly. See this:
29
+ To use Season scopes just append `_before`, `_after` or `_between` to your date/datetime/timestamp column names and pass the arguments accordingly. See this:
30
30
 
31
31
  First, include Season in your model(s):
32
32
  ```ruby
@@ -36,6 +36,8 @@ class User < ActiveRecord::Base
36
36
  end
37
37
  ```
38
38
 
39
+ ### Scopes
40
+
39
41
  Now, considering that our `User` class has three datetime columns named `:created_at`, `:updated_at` and `:confirmed_at`, the following scopes will be automatically available:
40
42
  ```ruby
41
43
  # * Time/DateTime/String instances are allowed as arguments.
@@ -43,14 +45,17 @@ Now, considering that our `User` class has three datetime columns named `:create
43
45
  User.created_at_before(Time.now)
44
46
  User.created_at_after(DateTime.now)
45
47
  User.created_at_between(Time.now - 1.week, '31-01-2015')
48
+ # => [ActiveRecord::Relation of Users]
46
49
 
47
50
  User.updated_at_before(DateTime.now)
48
51
  User.updated_at_after('01-01-2015')
49
52
  User.updated_at_between(Time.now - 1.week, Time.now)
53
+ # => [ActiveRecord::Relation of Users]
50
54
 
51
55
  User.confirmed_at_before('01-01-2015')
52
56
  User.confirmed_at_after(DateTime.now)
53
57
  User.confirmed_at_between(Time.now - 1.year, Time.now - 1.week)
58
+ # => [ActiveRecord::Relation of Users]
54
59
  ```
55
60
 
56
61
  They are chainable, so you can also do things like this:
@@ -59,13 +64,21 @@ User.where(id: [1, 2, 3]).created_before(Time.now)
59
64
  User.updated_after('01-01-2015').order(created_at: :asc)
60
65
  ```
61
66
 
67
+ ### Instance methods
68
+
69
+ Other than scopes, useful instance methos will also be available:
70
+ ```ruby
71
+ joe = User.first
72
+
73
+ joe.created_at_before?(Time.now)
74
+ joe.updated_at_after?('10-10-2000')
75
+ joe.confirmed_at_between?('20-10-2013', DateTime.now)
76
+ # => true or false
77
+ ```
78
+
62
79
  ## To Do
63
80
 
64
- - Even more tests
65
- - Support other ORMs (Mongoid, 'insert-more-here')
66
- - Add Error Handling
67
- - Add helpers for instances (like `User.first.created_before?('01-02-2015')`)
68
- - Add support for queries with joins
81
+ - Support other ORMs (Mongoid, ...?)
69
82
 
70
83
  ## Contributing
71
84
 
@@ -3,6 +3,7 @@ require "season/configuration"
3
3
  require "season/legacy"
4
4
  require "season/scope_builder"
5
5
  require "season/query_builder"
6
+ require "season/instance_method_builder"
6
7
 
7
8
  module Season
8
9
 
@@ -11,22 +12,35 @@ module Season
11
12
  def self.included(base)
12
13
  base.extend(ClassMethods)
13
14
 
14
- mb = ScopeBuilder.new(base)
15
+ # Define scopes
16
+ sb = ScopeBuilder.new(base)
17
+ base.class_eval do
18
+ base.date_or_time_column_names.each do |column_name|
19
+ QUERY_VERBS.each do |query_verb|
20
+ sb.build(table_name, column_name, query_verb)
21
+ end
22
+ end
23
+ end
15
24
 
25
+ # Define instance methods
26
+ imb = InstanceMethodBuilder.new(base)
16
27
  base.class_eval do
17
- # DEFINE SCOPES DINAMICALLY
18
- base.datetime_column_names.each do |column_name|
28
+ base.date_or_time_column_names.each do |column_name|
19
29
  QUERY_VERBS.each do |query_verb|
20
- mb.build(table_name, column_name, query_verb)
30
+ imb.build(table_name, column_name, query_verb)
21
31
  end
22
32
  end
23
33
  end
24
34
  end
25
35
 
26
36
  module ClassMethods
27
- def datetime_column_names
28
- columns.map { |c| c.name if c.type == :datetime }.compact
37
+ def date_or_time_column_names
38
+ columns.map { |c| c.name if c.type == :datetime || c.type == :date }.compact
29
39
  end
30
40
  end
41
+
42
+ def self.root
43
+ File.expand_path '../..', __FILE__
44
+ end
31
45
  end
32
46
 
@@ -0,0 +1,45 @@
1
+ module Season
2
+ class InstanceMethodBuilder
3
+
4
+ def initialize(klass)
5
+ @klass = klass
6
+ end
7
+
8
+ def build(table_name, column_name, query_verb)
9
+ method_val = self.send(query_verb, column_name)
10
+
11
+ @klass.class_eval %Q{
12
+ def #{column_name}_#{query_verb}?(*args)
13
+ #{method_val}
14
+ end
15
+ }
16
+ end
17
+
18
+ private
19
+
20
+ def parse_input(date_input)
21
+ date_input= case date_input.class
22
+ when Time || Date || ActiveSupport::TimeWithZone
23
+ date_input.to_i
24
+ when DateTime
25
+ date_input
26
+ when String
27
+ DateTime.parse(date_input)
28
+ else
29
+ raise ArgumentError, 'Invalid date_to_compare to compare.'
30
+ end
31
+ end
32
+
33
+ def before(column_name)
34
+ "#{column_name} < args.first"
35
+ end
36
+
37
+ def after(column_name)
38
+ "#{column_name} > args.first"
39
+ end
40
+
41
+ def between(column_name)
42
+ "#{column_name} > args.first || #{column_name} < args.last"
43
+ end
44
+ end
45
+ end
@@ -28,4 +28,5 @@ module Season
28
28
  end
29
29
  end
30
30
  end
31
- end
31
+ end
32
+
@@ -9,26 +9,28 @@ module Season
9
9
  def build(table_name, column_name, query_verb)
10
10
  unless method_exists?(column_name)
11
11
  query_str = @query_builder.build(table_name, column_name, query_verb)
12
-
13
- @klass.define_singleton_method "#{column_name}_#{query_verb}" do |*args|
14
- eval(query_str)
15
- end
12
+
13
+ @klass.instance_eval %Q{
14
+ def #{column_name}_#{query_verb}(*args)
15
+ #{query_str}
16
+ end
17
+ }
16
18
  end
17
19
  end
18
20
 
19
21
  private
20
22
 
21
- def method_exists?(column_name)
22
- defined? @klass.column_name
23
- end
23
+ def method_exists?(column_name)
24
+ defined? @klass.column_name
25
+ end
24
26
 
25
- def adapter_class_name
26
- return 'active_record' if @klass < ActiveRecord::Base
27
- raise "Database adapter not supported."
28
- end
27
+ def adapter_class_name
28
+ return 'active_record' if @klass < ActiveRecord::Base
29
+ raise "Database adapter not supported."
30
+ end
29
31
 
30
- # def remove_old_suffix(text)
31
- # text.sub(/(#{POPULAR_SUFFIXES.join('|')})$/, '') || text
32
- # end
33
- end
32
+ # def remove_old_suffix(text)
33
+ # text.sub(/(#{POPULAR_SUFFIXES.join('|')})$/, '') || text
34
+ # end
35
+ end
34
36
  end
@@ -1,3 +1,3 @@
1
1
  module Season
2
- VERSION = "0.2"
2
+ VERSION = "0.3"
3
3
  end
@@ -26,5 +26,6 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "activerecord", "~> 4.0"
27
27
  spec.add_development_dependency "rubocop", "~> 0.29"
28
28
  spec.add_development_dependency "rubocop-rspec", "~> 1.2"
29
- spec.add_development_dependency "sqlite3", "~> 1.3"
29
+ spec.add_development_dependency "sqlite3", "~> 1.3"
30
+ spec.add_development_dependency "database_cleaner", "~> 1.4"
30
31
  end
@@ -12,6 +12,7 @@ ActiveRecord::Base.connection.instance_eval do
12
12
  create_table :users do |t|
13
13
  t.datetime :created_at
14
14
  t.datetime :updated_at
15
+ t.date :birthdate
15
16
  t.timestamp :confirmed_at
16
17
  end
17
18
  end
@@ -27,28 +28,95 @@ end
27
28
  RSpec.describe Season do
28
29
  subject { User }
29
30
 
30
- it 'has scopes to datetime columns of datetime type' do
31
- expect(subject).to respond_to(:created_at_before, :created_at_after)
32
- .with(1).argument
33
- expect(subject).to respond_to(:created_at_between).with(2).arguments
31
+ describe 'defined datetime scopes' do
32
+ it 'of datetime type' do
33
+ expect(subject).to respond_to(:created_at_before, :created_at_after)
34
+ .with(1).argument
35
+ expect(subject).to respond_to(:created_at_between).with(2).arguments
36
+ end
37
+
38
+ it 'of date type' do
39
+ expect(subject).to respond_to(:birthdate_before, :birthdate_after)
40
+ .with(1).argument
41
+ expect(subject).to respond_to(:birthdate_between).with(2).arguments
42
+ end
43
+
44
+ it 'of timestamp type' do
45
+ expect(subject).to respond_to(:confirmed_at_before, :confirmed_at_after)
46
+ .with(1).argument
47
+ expect(subject).to respond_to(:confirmed_at_between).with(2).arguments
48
+ end
49
+
50
+ it ' - legacy' do
51
+ expect(subject).to respond_to(:created_before, :created_after)
52
+ .with(1).argument
53
+ expect(subject).to respond_to(:created_between).with(2).arguments
54
+ expect(subject).to respond_to(:updated_before, :updated_after)
55
+ .with(1).argument
56
+ expect(subject).to respond_to(:updated_between).with(2).arguments
57
+ end
34
58
  end
35
59
 
36
- it 'has scopes to datetime columns of timestamp type' do
37
- expect(subject).to respond_to(:confirmed_at_before, :confirmed_at_after)
38
- .with(1).argument
39
- expect(subject).to respond_to(:confirmed_at_between).with(2).arguments
60
+ describe 'datetime scopes' do
61
+
62
+ let(:instant) { DateTime.parse('01-01-2015') }
63
+
64
+ before do
65
+ User.create!(created_at: instant - 1.year)
66
+ User.create!(created_at: instant + 1.year)
67
+ end
68
+
69
+ it "shows correct results for 'before'" do
70
+ expect(subject.created_at_before(instant).count).to eq(1)
71
+ end
72
+
73
+ it "shows correct results for 'after'" do
74
+ expect(subject.created_at_after(instant).count).to eq(1)
75
+ end
76
+
77
+ it "shows correct results for 'between'" do
78
+ expect(subject.created_at_between(instant - 2.year, instant + 2.year).count).to eq(2)
79
+ end
40
80
  end
41
81
 
42
- it 'has legacy scopes' do
43
- expect(subject).to respond_to(:created_before, :created_after)
44
- .with(1).argument
45
- expect(subject).to respond_to(:created_between).with(2).arguments
46
- expect(subject).to respond_to(:updated_before, :updated_after)
47
- .with(1).argument
48
- expect(subject).to respond_to(:updated_between).with(2).arguments
82
+ describe 'defined datetime instance methods' do
83
+
84
+ let(:user) { User.new }
85
+
86
+ it 'of datetime type' do
87
+ expect(user).to respond_to(:created_at_before?, :created_at_after?)
88
+ .with(1).argument
89
+ expect(user).to respond_to(:created_at_between?).with(2).arguments
90
+ end
91
+
92
+ it 'of date type' do
93
+ expect(user).to respond_to(:birthdate_before?, :birthdate_after?)
94
+ .with(1).argument
95
+ expect(user).to respond_to(:birthdate_between?).with(2).arguments
96
+ end
97
+
98
+ it 'of timestamp type' do
99
+ expect(user).to respond_to(:confirmed_at_before?, :confirmed_at_after?)
100
+ .with(1).argument
101
+ expect(user).to respond_to(:confirmed_at_between?).with(2).arguments
102
+ end
49
103
  end
50
104
 
51
- it 'has legacy scopes' do
52
- expect(subject.created_at_before(Time.now)).to eq([])
105
+ describe 'datetime instance methods' do
106
+
107
+ let(:instant) { DateTime.parse('01-01-2015') }
108
+ let(:user) { User.create!(created_at: instant) }
109
+
110
+ it "shows correct results for 'before'" do
111
+ expect(user.created_at_before?(instant + 1.day)).to eq(true)
112
+ end
113
+
114
+ it "shows correct results for 'after'" do
115
+ expect(user.created_at_after?(instant - 1.day)).to eq(true)
116
+ end
117
+
118
+ it "shows correct results for 'between'" do
119
+ expect(user.created_at_between?(instant - 1.day, instant + 1.day)).to eq(true)
120
+ end
53
121
  end
54
122
  end
@@ -1,4 +1,5 @@
1
1
  require 'season'
2
+ require 'database_cleaner'
2
3
  require "codeclimate-test-reporter"
3
4
  CodeClimate::TestReporter.start
4
5
 
@@ -10,4 +11,17 @@ RSpec.configure do |config|
10
11
  config.mock_with :rspec do |mocks|
11
12
  mocks.verify_partial_doubles = true
12
13
  end
14
+
15
+ config.before(:suite) do
16
+ DatabaseCleaner.strategy = :truncation
17
+ DatabaseCleaner.clean_with :truncation
18
+ end
19
+
20
+ config.before(:each) do
21
+ DatabaseCleaner.start
22
+ end
23
+
24
+ config.after(:each) do
25
+ DatabaseCleaner.clean
26
+ end
13
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: season
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joao Diogo Costa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-10 00:00:00.000000000 Z
11
+ date: 2015-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '1.3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: database_cleaner
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.4'
111
125
  description: Season automatically creates scopes for your models' datetime columns.
112
126
  email:
113
127
  - jdscosta91@gmail.com
@@ -125,6 +139,7 @@ files:
125
139
  - Rakefile
126
140
  - lib/season.rb
127
141
  - lib/season/configuration.rb
142
+ - lib/season/instance_method_builder.rb
128
143
  - lib/season/legacy.rb
129
144
  - lib/season/query_builder.rb
130
145
  - lib/season/scope_builder.rb