season 0.2 → 0.3

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: 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