├── .gitignore ├── .rspec ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── datetime-scopes.gemspec ├── lib ├── datetime-scopes.rb └── datetime-scopes │ ├── abstract_proxy.rb │ ├── active_record_extension.rb │ ├── date_proxy.rb │ ├── datetime_proxy.rb │ └── version.rb ├── log └── .gitkeep └── spec ├── datetime-scopes ├── date_scopes_spec.rb └── datetime_scopes_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /Gemfile.lock 2 | /.bundle 3 | /pkg 4 | /log/* 5 | !/log/.gitkeep 6 | .ruby-version 7 | .ruby-gemset 8 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format=doc 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | rvm: 4 | - 2.3.0 5 | 6 | addons: 7 | code_climate: 8 | repo_token: ca3a5a1d9af873ba0b6c6fa198a1e9e10c12c738211243d279181f58ca2c73ea 9 | 10 | env: 11 | matrix: 12 | - RAILS_VERSION=4.0.0 13 | - RAILS_VERSION=4.1.0 14 | - RAILS_VERSION=4.2.0 15 | 16 | script: "bundle exec rspec --format=progress --no-color" 17 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | if ENV["RAILS_VERSION"] 4 | gem "activerecord", "~> #{ENV["RAILS_VERSION"]}" 5 | gem "activesupport", "~> #{ENV["RAILS_VERSION"]}" 6 | end 7 | 8 | gem "sqlite3" 9 | gem "rspec", "~> 3.4.0" 10 | gem "database_cleaner" 11 | gem "codeclimate-test-reporter" 12 | 13 | gemspec 14 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Alexey Chernenkov 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. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Date/time scopes for ActiveRecord models 2 | 3 | [![Gem Version](https://badge.fury.io/rb/datetime-scopes.svg)](https://badge.fury.io/rb/datetime-scopes) 4 | [![Build Status](https://travis-ci.org/907th/datetime-scopes.svg?branch=master)](https://travis-ci.org/907th/datetime-scopes) 5 | [![Code Climate](https://codeclimate.com/github/907th/datetime-scopes/badges/gpa.svg)](https://codeclimate.com/github/907th/datetime-scopes) 6 | [![Test Coverage](https://codeclimate.com/github/907th/datetime-scopes/badges/coverage.svg)](https://codeclimate.com/github/907th/datetime-scopes/coverage) 7 | 8 | Date/time scopes for ActiveRecord models you always missed! With proper time-zones support. 9 | 10 | ## Quick start 11 | 12 | ```ruby 13 | # Gemfile 14 | gem "datetime-scopes" 15 | ``` 16 | 17 | ```ruby 18 | # app/models/my_model.rb 19 | class MyModel < ActiveRecord::Base 20 | datetime_scopes :created_at # with 'datetime' typed attribute 21 | date_scopes :birthday # with 'date' typed attribute 22 | end 23 | ``` 24 | 25 | Now your model has these scopes: 26 | 27 | 28 | 29 | 32 | 35 | 36 | 37 | 64 | 86 | 87 |
30 | for created_at 31 | 33 | for birthday 34 |
38 |
    39 |
  • created_within(from, to)
  • 40 |
  • created_within_days(from, to)
  • 41 |
  • created_within_months(from, to)
  • 42 |
  • created_within_years(from, to)
  • 43 |
  • created_on_day(t)
  • 44 |
  • created_on_month(t)
  • 45 |
  • created_on_year(t)
  • 46 |
  • created_before(t)
  • 47 |
  • created_before_day(t)
  • 48 |
  • created_before_month(t)
  • 49 |
  • created_before_year(t)
  • 50 |
  • created_after(t)
  • 51 |
  • created_after_day(t)
  • 52 |
  • created_after_month(t)
  • 53 |
  • created_after_year(t)
  • 54 |
  • created_on_or_before(t)
  • 55 |
  • created_on_or_before_day(t)
  • 56 |
  • created_on_or_before_month(t)
  • 57 |
  • created_on_or_before_year(t)
  • 58 |
  • created_on_or_after(t)
  • 59 |
  • created_on_or_after_day(t)
  • 60 |
  • created_on_or_after_month(t)
  • 61 |
  • created_on_or_after_year(t)
  • 62 |
63 |
65 |
    66 |
  • birthday_within_days(from, to)
  • 67 |
  • birthday_within_months(from, to)
  • 68 |
  • birthday_within_years(from, to)
  • 69 |
  • birthday_on_day(t)
  • 70 |
  • birthday_on_month(t)
  • 71 |
  • birthday_on_year(t)
  • 72 |
  • birthday_before_day(t)
  • 73 |
  • birthday_before_month(t)
  • 74 |
  • birthday_before_year(t)
  • 75 |
  • birthday_after_day(t)
  • 76 |
  • birthday_after_month(t)
  • 77 |
  • birthday_after_year(t)
  • 78 |
  • birthday_on_or_before_day(t)
  • 79 |
  • birthday_on_or_before_month(t)
  • 80 |
  • birthday_on_or_before_year(t)
  • 81 |
  • birthday_on_or_after_day(t)
  • 82 |
  • birthday_on_or_after_month(t)
  • 83 |
  • birthday_on_or_after_year(t)
  • 84 |
85 |
88 | 89 | Examples: 90 | 91 | ```ruby 92 | # All records created yesterday (in current `::Time.zone`) 93 | MyModel.created_on_day(Date.yesterday) 94 | 95 | # Records created since 11 Sep 2001 (in current `::Time.zone`) 96 | MyModel.created_on_or_after("2001.09.11") 97 | 98 | # Records create since 11 Sep 2001 (in New York). Yes, the result may differ to previous example! 99 | MyModel.created_on_or_after("2001.09.11", time_zone: "Eastern Time (US & Canada)") 100 | 101 | # Records with birthday in 2015 102 | MyModel.birthday_on_year(Date.new 2015) 103 | ``` 104 | 105 | ## Time-zone support 106 | 107 | You know, when it is Sunday in San Francisco, it is Monday in Manila! 108 | All parameters passed to a date/time scopes are first converted to a 109 | project-specific (`::Time.zone`) or specified (`time_zone: "XXX"` param) time-zone with the help 110 | of magic ActiveSupport's `#in_time_zone` helper. See `rake time:zones:all` for 111 | all supported time-zones. 112 | 113 | ## Additional options 114 | 115 | You can pass a default time-zone and custom scopes' prefix to a `date(time)_scopes` method: 116 | 117 | ```ruby 118 | # app/models/my_model.rb 119 | class MyModel < ActiveRecord::Base 120 | datetime_scopes :created_at, prefix: "issued", time_zone: "Ekaterinburg" 121 | end 122 | 123 | # All records created yesterday (in Ekaterinburg) 124 | MyModel.issued_on_day(Date.yesterday) 125 | ``` 126 | 127 | ## TODO 128 | 129 | - Complete pending tests! 130 | - ... 131 | 132 | ## Contributing 133 | 134 | Any feedback is welcome! 135 | 136 | ## License 137 | 138 | Distributed under the MIT License (see LICENSE.txt). 139 | 140 | Copyright © 2015. Alexey Chernenkov 141 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /datetime-scopes.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path("../lib", __FILE__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require "datetime-scopes/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "datetime-scopes" 7 | spec.version = DateTimeScopes::VERSION 8 | spec.authors = ["Alexey Chernenkov"] 9 | spec.email = ["laise@pisem.net"] 10 | spec.summary = "Date/time scopes for ActiveRecord models you always missed!" 11 | spec.description = spec.summary 12 | spec.homepage = "https://github.com/907th/datetime-scopes" 13 | spec.license = "MIT" 14 | 15 | spec.files = `git ls-files -z`.split("\x0") 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 18 | spec.require_paths = ["lib"] 19 | 20 | spec.add_development_dependency "bundler", "~> 1.11.2" 21 | spec.add_development_dependency "rake", "~> 10.4.2" 22 | 23 | spec.add_dependency "activerecord", ">= 4.0" 24 | spec.add_dependency "activesupport", ">= 4.0" 25 | end 26 | -------------------------------------------------------------------------------- /lib/datetime-scopes.rb: -------------------------------------------------------------------------------- 1 | require "active_record" 2 | require "active_support/core_ext/date" 3 | require "active_support/core_ext/time" 4 | require "active_support/core_ext/date_time" 5 | 6 | require "datetime-scopes/active_record_extension" 7 | 8 | ActiveRecord::Base.send :include, DateTimeScopes::ActiveRecordExtension 9 | -------------------------------------------------------------------------------- /lib/datetime-scopes/abstract_proxy.rb: -------------------------------------------------------------------------------- 1 | module DateTimeScopes 2 | class AbstractProxy 3 | def initialize(attribute:, time_zone:) 4 | @attribute = attribute 5 | @time_zone = time_zone 6 | end 7 | 8 | def proxy_methods 9 | raise "Must be implemented in sub-class" 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/datetime-scopes/active_record_extension.rb: -------------------------------------------------------------------------------- 1 | require_relative "datetime_proxy" 2 | require_relative "date_proxy" 3 | 4 | module DateTimeScopes 5 | module ActiveRecordExtension 6 | def self.included(base) 7 | base.extend ClassMethods 8 | end 9 | 10 | module ClassMethods 11 | def datetime_scopes(attr, prefix: nil, time_zone: ::Time.zone) 12 | proxy = DateTimeProxy.new( 13 | attribute: "#{table_name}.#{attr}", 14 | time_zone: time_zone 15 | ) 16 | prefix = datetime_scope_prefix(attr) if prefix.nil? 17 | declare_datetime_scopes prefix, proxy 18 | end 19 | 20 | def date_scopes(attr, prefix: nil, time_zone: nil) 21 | proxy = DateProxy.new( 22 | attribute: "#{table_name}.#{attr}", 23 | time_zone: time_zone 24 | ) 25 | prefix = datetime_scope_prefix(attr) if prefix.nil? 26 | declare_datetime_scopes prefix, proxy 27 | end 28 | 29 | private 30 | 31 | def declare_datetime_scopes(prefix, proxy) 32 | proxy.proxy_methods.each do |method_name| 33 | scope_name = "#{prefix}_#{method_name}" 34 | scope scope_name, -> (*attrs) { proxy.send method_name, self, *attrs } 35 | end 36 | end 37 | 38 | def datetime_scope_prefix(attr) 39 | attr.to_s.sub /_(at|on|time|date)$/, "" 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/datetime-scopes/date_proxy.rb: -------------------------------------------------------------------------------- 1 | require_relative "abstract_proxy" 2 | 3 | module DateTimeScopes 4 | class DateProxy < AbstractProxy 5 | PROXY_METHODS = %w[ 6 | within_days 7 | within_months 8 | within_years 9 | on_day 10 | on_month 11 | on_year 12 | before_day 13 | before_month 14 | before_year 15 | after_day 16 | after_month 17 | after_year 18 | on_or_before_day 19 | on_or_before_month 20 | on_or_before_year 21 | on_or_after_day 22 | on_or_after_month 23 | on_or_after_year 24 | ].freeze 25 | 26 | def proxy_methods 27 | PROXY_METHODS 28 | end 29 | 30 | # Intervals 31 | 32 | def within_days(rel, from, to, time_zone: @time_zone) 33 | rel.where( 34 | "#{@attribute} >= ? AND #{@attribute} <= ?", 35 | from.in_time_zone(time_zone).to_date, 36 | to.in_time_zone(time_zone).to_date 37 | ) 38 | end 39 | 40 | def within_months(rel, from, to, time_zone: @time_zone) 41 | within_days( 42 | rel, 43 | from.in_time_zone(time_zone).beginning_of_month, 44 | to.in_time_zone(time_zone).end_of_month, 45 | time_zone: time_zone 46 | ) 47 | end 48 | 49 | def within_years(rel, from, to, time_zone: @time_zone) 50 | within_days( 51 | rel, 52 | from.in_time_zone(time_zone).beginning_of_year, 53 | to.in_time_zone(time_zone).end_of_year, 54 | time_zone: time_zone 55 | ) 56 | end 57 | 58 | # Specific day/month/year 59 | 60 | def on_day(rel, day, time_zone: @time_zone) 61 | within_days rel, day, day, time_zone: time_zone 62 | end 63 | 64 | def on_month(rel, month, time_zone: @time_zone) 65 | within_months rel, month, month, time_zone: time_zone 66 | end 67 | 68 | def on_year(rel, year, time_zone: @time_zone) 69 | within_years rel, year, year, time_zone: time_zone 70 | end 71 | 72 | # Strict equations 73 | 74 | def before_day(rel, day, time_zone: @time_zone) 75 | rel.where "#{@attribute} < ?", day.in_time_zone(time_zone).to_date 76 | end 77 | 78 | def before_month(rel, month, time_zone: @time_zone) 79 | before_day rel, month.in_time_zone(time_zone).beginning_of_month, time_zone: time_zone 80 | end 81 | 82 | def before_year(rel, year, time_zone: @time_zone) 83 | before_day rel, year.in_time_zone(time_zone).beginning_of_year, time_zone: time_zone 84 | end 85 | 86 | def after_day(rel, day, time_zone: @time_zone) 87 | rel.where "#{@attribute} > ?", day.in_time_zone(time_zone).to_date 88 | end 89 | 90 | def after_month(rel, month, time_zone: @time_zone) 91 | after_day rel, month.in_time_zone(time_zone).end_of_month, time_zone: time_zone 92 | end 93 | 94 | def after_year(rel, year, time_zone: @time_zone) 95 | after_day rel, year.in_time_zone(time_zone).end_of_year, time_zone: time_zone 96 | end 97 | 98 | # Non-strict equations 99 | 100 | def on_or_before_day(rel, day, time_zone: @time_zone) 101 | rel.where "#{@attribute} <= ?", day.in_time_zone(time_zone).to_date 102 | end 103 | 104 | def on_or_before_month(rel, month, time_zone: @time_zone) 105 | on_or_before_day rel, month.in_time_zone(time_zone).end_of_month, time_zone: time_zone 106 | end 107 | 108 | def on_or_before_year(rel, year, time_zone: @time_zone) 109 | on_or_before_day rel, year.in_time_zone(time_zone).end_of_year, time_zone: time_zone 110 | end 111 | 112 | def on_or_after_day(rel, day, time_zone: @time_zone) 113 | rel.where "#{@attribute} >= ?", day.in_time_zone(time_zone).to_date 114 | end 115 | 116 | def on_or_after_month(rel, month, time_zone: @time_zone) 117 | on_or_after_day rel, month.in_time_zone(time_zone).beginning_of_month, time_zone: time_zone 118 | end 119 | 120 | def on_or_after_year(rel, year, time_zone: @time_zone) 121 | on_or_after_day rel, year.in_time_zone(time_zone).beginning_of_year, time_zone: time_zone 122 | end 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /lib/datetime-scopes/datetime_proxy.rb: -------------------------------------------------------------------------------- 1 | require_relative "abstract_proxy" 2 | 3 | module DateTimeScopes 4 | class DateTimeProxy < AbstractProxy 5 | PROXY_METHODS = %w[ 6 | within 7 | within_days 8 | within_months 9 | within_years 10 | on_day 11 | on_month 12 | on_year 13 | before 14 | before_day 15 | before_month 16 | before_year 17 | after 18 | after_day 19 | after_month 20 | after_year 21 | on_or_before 22 | on_or_before_day 23 | on_or_before_month 24 | on_or_before_year 25 | on_or_after 26 | on_or_after_day 27 | on_or_after_month 28 | on_or_after_year 29 | ].freeze 30 | 31 | def proxy_methods 32 | PROXY_METHODS 33 | end 34 | 35 | # Intervals 36 | 37 | def within(rel, from, to, time_zone: @time_zone) 38 | rel.where( 39 | "#{@attribute} >= ? AND #{@attribute} <= ?", 40 | from.in_time_zone(time_zone), 41 | to.in_time_zone(time_zone) 42 | ) 43 | end 44 | 45 | def within_days(rel, from, to, time_zone: @time_zone) 46 | within( 47 | rel, 48 | from.in_time_zone(time_zone).beginning_of_day, 49 | to.in_time_zone(time_zone).end_of_day, 50 | time_zone: time_zone 51 | ) 52 | end 53 | 54 | def within_months(rel, from, to, time_zone: @time_zone) 55 | within( 56 | rel, 57 | from.in_time_zone(time_zone).beginning_of_month, 58 | to.in_time_zone(time_zone).end_of_month, 59 | time_zone: time_zone 60 | ) 61 | end 62 | 63 | def within_years(rel, from, to, time_zone: @time_zone) 64 | within( 65 | rel, 66 | from.in_time_zone(time_zone).beginning_of_year, 67 | to.in_time_zone(time_zone).end_of_year, 68 | time_zone: time_zone 69 | ) 70 | end 71 | 72 | # Specific day/month/year 73 | 74 | def on_day(rel, day, time_zone: @time_zone) 75 | within_days rel, day, day, time_zone: time_zone 76 | end 77 | 78 | def on_month(rel, month, time_zone: @time_zone) 79 | within_months rel, month, month, time_zone: time_zone 80 | end 81 | 82 | def on_year(rel, year, time_zone: @time_zone) 83 | within_years rel, year, year, time_zone: time_zone 84 | end 85 | 86 | # Strict equations 87 | 88 | def before(rel, time, time_zone: @time_zone) 89 | rel.where "#{@attribute} < ?", time.in_time_zone(time_zone) 90 | end 91 | 92 | def before_day(rel, day, time_zone: @time_zone) 93 | before rel, day.in_time_zone(time_zone).beginning_of_day, time_zone: time_zone 94 | end 95 | 96 | def before_month(rel, month, time_zone: @time_zone) 97 | before rel, month.in_time_zone(time_zone).beginning_of_month, time_zone: time_zone 98 | end 99 | 100 | def before_year(rel, year, time_zone: @time_zone) 101 | before rel, year.in_time_zone(time_zone).beginning_of_year, time_zone: time_zone 102 | end 103 | 104 | def after(rel, time, time_zone: @time_zone) 105 | rel.where "#{@attribute} > ?", time.in_time_zone(time_zone) 106 | end 107 | 108 | def after_day(rel, day, time_zone: @time_zone) 109 | after rel, day.in_time_zone(time_zone).end_of_day, time_zone: time_zone 110 | end 111 | 112 | def after_month(rel, month, time_zone: @time_zone) 113 | after rel, month.in_time_zone(time_zone).end_of_month, time_zone: time_zone 114 | end 115 | 116 | def after_year(rel, year, time_zone: @time_zone) 117 | after rel, year.in_time_zone(time_zone).end_of_year, time_zone: time_zone 118 | end 119 | 120 | # Non-strict equations 121 | 122 | def on_or_before(rel, time, time_zone: @time_zone) 123 | rel.where "#{@attribute} <= ?", time.in_time_zone(time_zone) 124 | end 125 | 126 | def on_or_before_day(rel, day, time_zone: @time_zone) 127 | on_or_before rel, day.in_time_zone(time_zone).end_of_day, time_zone: time_zone 128 | end 129 | 130 | def on_or_before_month(rel, month, time_zone: @time_zone) 131 | on_or_before rel, month.in_time_zone(time_zone).end_of_month, time_zone: time_zone 132 | end 133 | 134 | def on_or_before_year(rel, year, time_zone: @time_zone) 135 | on_or_before rel, year.in_time_zone(time_zone).end_of_year, time_zone: time_zone 136 | end 137 | 138 | def on_or_after(rel, time, time_zone: @time_zone) 139 | rel.where "#{@attribute} >= ?", time.in_time_zone(time_zone) 140 | end 141 | 142 | def on_or_after_day(rel, day, time_zone: @time_zone) 143 | on_or_after rel, day.in_time_zone(time_zone).beginning_of_day, time_zone: time_zone 144 | end 145 | 146 | def on_or_after_month(rel, month, time_zone: @time_zone) 147 | on_or_after rel, month.in_time_zone(time_zone).beginning_of_month, time_zone: time_zone 148 | end 149 | 150 | def on_or_after_year(rel, year, time_zone: @time_zone) 151 | on_or_after rel, year.in_time_zone(time_zone).beginning_of_year, time_zone: time_zone 152 | end 153 | end 154 | end 155 | -------------------------------------------------------------------------------- /lib/datetime-scopes/version.rb: -------------------------------------------------------------------------------- 1 | module DateTimeScopes 2 | VERSION = "1.0.0.alpha2" 3 | end 4 | -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/907th/datetime-scopes/2975605ee84b9b8fbd0fa01b7eac6419591d8d9b/log/.gitkeep -------------------------------------------------------------------------------- /spec/datetime-scopes/date_scopes_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | RSpec.describe "date_scopes" do 4 | pending "#within_days" 5 | pending "#within_months" 6 | pending "#within_years" 7 | pending "#on_day" 8 | pending "#on_month" 9 | pending "#on_year" 10 | pending "#before_day" 11 | pending "#before_month" 12 | pending "#before_year" 13 | pending "#after_day" 14 | pending "#after_month" 15 | pending "#after_year" 16 | pending "#on_or_before_day" 17 | pending "#on_or_before_month" 18 | pending "#on_or_before_year" 19 | pending "#on_or_after_day" 20 | pending "#on_or_after_month" 21 | pending "#on_or_after_year" 22 | end 23 | -------------------------------------------------------------------------------- /spec/datetime-scopes/datetime_scopes_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | RSpec.describe "datetime_scopes" do 4 | def self.test(method_name, params:, matching:, not_matching:) 5 | describe "##{method_name}" do 6 | let!(:method_name) { "foo_#{method_name}" } 7 | let!(:params) { params } 8 | let!(:matching) { matching } 9 | let!(:not_matching) { not_matching } 10 | 11 | before do 12 | (matching + not_matching).each do |t| 13 | FooBar.create! foo: t.in_time_zone 14 | end 15 | end 16 | 17 | def perform 18 | FooBar.send method_name, *params 19 | end 20 | 21 | it "includes matching times" do 22 | ret = perform.to_a.map(&:foo) 23 | matching.map(&:in_time_zone).each do |t| 24 | expect(ret).to include(t) 25 | end 26 | end 27 | 28 | it "doesn't include not matching times" do 29 | ret = perform.to_a.map(&:foo) 30 | not_matching.map(&:in_time_zone).each do |t| 31 | expect(ret).not_to include(t) 32 | end 33 | end 34 | end 35 | end 36 | 37 | test( 38 | "within", 39 | params: ["11.01.2015 23:41:35", "12.01.2015 01:00:23"], 40 | matching: [ 41 | "11.01.2015 23:41:35", 42 | "12.01.2015 00:40:01", 43 | "12.01.2015 01:00:23" 44 | ], 45 | not_matching: [ 46 | "11.01.2015 23:41:34", 47 | "12.01.2015 01:00:24" 48 | ] 49 | ) 50 | 51 | test( 52 | "within_days", 53 | params: ["11.01.2015 23:41:35", "12.01.2015 01:00:23"], 54 | matching: [ 55 | "11.01.2015 00:00:00", 56 | "11.01.2015 23:55:01", 57 | "12.01.2015 00:00:01", 58 | "12.01.2015 23:59:59" 59 | ], 60 | not_matching: [ 61 | "10.01.2014", 62 | "10.01.2015 23:59:59", 63 | "13.01.2015 00:00:00", 64 | "24.07.2015" 65 | ] 66 | ) 67 | 68 | test( 69 | "within_months", 70 | params: ["11.01.2015 23:41:35", "12.03.2015 01:00:23"], 71 | matching: [ 72 | "01.01.2015 00:00:00", 73 | "12.01.2015 23:55:01", 74 | "12.02.2015 12:05:21", 75 | "31.03.2015 23:59:59" 76 | ], 77 | not_matching: [ 78 | "10.12.2014", 79 | "31.12.2014 23:59:59", 80 | "01.04.2015 00:00:00", 81 | "24.07.2015" 82 | ] 83 | ) 84 | 85 | test( 86 | "within_years", 87 | params: ["11.01.2014 23:41:35", "12.03.2015 01:00:23"], 88 | matching: [ 89 | "01.01.2014 00:00:00", 90 | "12.07.2014 23:55:01", 91 | "17.05.2015 12:05:21", 92 | "31.12.2015 23:59:59" 93 | ], 94 | not_matching: [ 95 | "10.12.2012", 96 | "31.12.2013 23:59:59", 97 | "01.01.2016 00:00:00", 98 | "24.07.2016" 99 | ] 100 | ) 101 | 102 | test( 103 | "on_day", 104 | params: ["11.03.2014"], 105 | matching: [ 106 | "11.03.2014 00:00:00", 107 | "11.03.2014 13:55:01", 108 | "11.03.2014 23:59:59" 109 | ], 110 | not_matching: [ 111 | "10.03.2014", 112 | "10.03.2014 23:59:59", 113 | "12.03.2014 00:00:00", 114 | "13.03.2014" 115 | ] 116 | ) 117 | 118 | test( 119 | "on_month", 120 | params: ["11.03.2014"], 121 | matching: [ 122 | "01.03.2014 00:00:00", 123 | "12.03.2014 13:55:01", 124 | "31.03.2014 23:59:59" 125 | ], 126 | not_matching: [ 127 | "28.02.2014", 128 | "28.02.2014 23:59:59", 129 | "01.04.2014 00:00:00", 130 | "02.04.2014" 131 | ] 132 | ) 133 | 134 | test( 135 | "on_year", 136 | params: ["11.03.2014"], 137 | matching: [ 138 | "01.01.2014 00:00:00", 139 | "01.03.2014 13:55:01", 140 | "21.07.2014 13:55:01", 141 | "31.12.2014 23:59:59" 142 | ], 143 | not_matching: [ 144 | "31.12.2013", 145 | "31.12.2013 23:59:59", 146 | "01.01.2015 00:00:00", 147 | "02.01.2015" 148 | ] 149 | ) 150 | 151 | pending "#before" 152 | pending "#before_day" 153 | pending "#before_month" 154 | pending "#before_year" 155 | pending "#after" 156 | pending "#after_day" 157 | pending "#after_month" 158 | pending "#after_year" 159 | pending "#on_or_before" 160 | pending "#on_or_before_day" 161 | pending "#on_or_before_month" 162 | pending "#on_or_before_year" 163 | pending "#on_or_after" 164 | pending "#on_or_after_day" 165 | pending "#on_or_after_month" 166 | pending "#on_or_after_year" 167 | end 168 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "logger" 2 | logger = Logger.new(File.expand_path "../../log/test.log", __FILE__) 3 | logger.level = Logger::DEBUG 4 | 5 | require "codeclimate-test-reporter" 6 | CodeClimate::TestReporter.configure do |config| 7 | config.logger = logger 8 | end 9 | CodeClimate::TestReporter.start 10 | 11 | require "rspec/core" 12 | require "database_cleaner" 13 | require "datetime-scopes" 14 | 15 | ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:" 16 | ActiveRecord::Base.logger = logger 17 | DatabaseCleaner.strategy = :truncation 18 | 19 | RSpec.configure do |c| 20 | c.before :suite do 21 | DatabaseCleaner.clean 22 | end 23 | c.after :example do 24 | DatabaseCleaner.clean 25 | end 26 | end 27 | 28 | 29 | # Create table and declare AR model 30 | 31 | ActiveRecord::Migration.verbose = false 32 | ActiveRecord::Migration.create_table :foo_bars do |t| 33 | t.datetime :foo 34 | t.date :bar 35 | end 36 | 37 | class FooBar < ActiveRecord::Base 38 | datetime_scopes :foo 39 | date_scopes :bar 40 | end 41 | --------------------------------------------------------------------------------