date_as_string 0.0.6

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
+ SHA256:
3
+ metadata.gz: f8bde9b4c771dda4f6270bb5270de295af06337e4352a55f425e4aaaa277ac21
4
+ data.tar.gz: '087b9878efd66ca01a9e60a5aa74fd7d6dc057edb680c570f70eaefcf6508878'
5
+ SHA512:
6
+ metadata.gz: 44c6573aee04ef19c850c36daabf1093ce2684fd266e48850fd51bab1f055acb214721960071c5b6932eb38467f8f7f42f4a692276254f0b094cd2a8eaafa13c
7
+ data.tar.gz: b029b37c736ef35ecad4e3ffe4cf1ef67c12f7e37b21a025831198cbb7be137ab3281620f8651b645ab69a2fa601d99d4a71297ee12feb3309843ff13dd12b2f
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
6
+ .DS_Store
7
+ *.log
8
+ *.sqlite
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in date_as_string.gemspec
4
+ gemspec
5
+
6
+
7
+ group :test do
8
+ gem 'activesupport'
9
+ gem 'byebug'
10
+ end
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ #Override bundler to prevent releasing to RubyGems
4
+ module Bundler
5
+ class GemHelper
6
+ def release_gem
7
+ guard_clean
8
+ guard_already_tagged
9
+ built_gem_path = build_gem
10
+ tag_version {
11
+ git_push
12
+ }
13
+ end
14
+ end
15
+ end
16
+
17
+ #http://asciicasts.com/episodes/245-new-gem-with-bundler
18
+ #$ rake -T
19
+ #rake build # Build mesav-#.#.#.gem into the pkg directory
20
+ #rake install # Build and install mesav-#.#.#.gem into system gems
21
+ #rake release # Create tag v#.#.#, build, and push
22
+
23
+ #RSPEC
24
+ require 'rspec/core/rake_task'
25
+
26
+ RSpec::Core::RakeTask.new('spec')
27
+
28
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "date_as_string/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "date_as_string"
7
+ s.version = DateAsString::VERSION::STRING
8
+ s.authors = ["Eric Sullivan"]
9
+ s.email = ["eric.sullivan@annkissam.com"]
10
+ s.homepage = "http://annkissam.com"
11
+ s.summary = %q{Convert from Date to String and vice versa by attaching _string suffix to an ActiveRecord field}
12
+ s.description = %q{Treat an ActiveRecord Date column as a String}
13
+
14
+ s.rubyforge_project = "date_as_string"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec"
22
+ end
@@ -0,0 +1,222 @@
1
+ require "date_as_string/version"
2
+
3
+ require "date_as_string/formats"
4
+
5
+ module DateAsString
6
+ def self.guess_century(year, cutoff=20)
7
+ century = get_century_from_year_range(year, cutoff)
8
+
9
+ century.present? ? century : raise_century_error
10
+ end
11
+
12
+ def self.included(base)
13
+ base.send(:extend, DateAsString::ClassMethods)
14
+ end
15
+
16
+ def self.parse_date(date)
17
+ date.respond_to?(:strftime) ? date.strftime('%m/%d/%Y') : nil
18
+ end
19
+
20
+ def self.parse_string(date_string)
21
+ begin
22
+ case
23
+ when t_regex.match(date_string)
24
+ date_for_t_match(date_string)
25
+ when mmddyy_regex.match(date_string)
26
+ date_for_mmddyy_match(date_string)
27
+ when mmddyy_regex(with_slashes: true).match(date_string)
28
+ date_for_mmddyy_match(date_string, with_slashes: true)
29
+ when mmddyyyy_regex.match(date_string)
30
+ date_for_mmddyyyy_match(date_string)
31
+ when mmddyyyy_regex(with_slashes: true).match(date_string)
32
+ date_for_mmddyyyy_match(date_string, with_slashes: true)
33
+ else
34
+ nil
35
+ end
36
+ rescue
37
+ nil
38
+ end
39
+ end
40
+
41
+ module ClassMethods
42
+ def date_as_string(*args)
43
+ defaults = {:input_formats => [:mm_dd_yyyy, :mm_dd_yyyy, :mmddyyyy, :mmddyy, :t_pmd],
44
+ :default_display_format => :mm_dd_yyyy,
45
+ :century_cutoff => 20,
46
+ :default => nil}
47
+ options = args.last.is_a?(Hash) ? defaults.merge(args.pop) : defaults
48
+
49
+ #We're current not doing anything with the options...
50
+ #We should support default formats, default value, and allowable formats...
51
+
52
+ unless self.respond_to?(:date_as_string_options)
53
+ cattr_accessor :date_as_string_options
54
+ self.date_as_string_options = {}
55
+ end
56
+
57
+ args.each do |attribute_name|
58
+ self.date_as_string_options[attribute_name] = options
59
+
60
+ validate :"#{attribute_name}_format"
61
+
62
+ define_method "#{attribute_name}_string" do |*display_format|
63
+ if instance_variable_get("@#{attribute_name}_string")
64
+ instance_variable_get("@#{attribute_name}_string")
65
+ else
66
+ if self.send("#{attribute_name}").nil?
67
+ if options[:default] && options[:default].is_a?(String)
68
+ eval(options[:default])
69
+ elsif options[:default] && options[:default].is_a?(Proc)
70
+ options[:default].call
71
+ else
72
+ nil
73
+ end
74
+ else
75
+ #self.send("#{attribute_name}").strftime('%m/%d/%Y')
76
+ unless display_format.empty?
77
+ DateAsString::Formats.find_format(display_format[0]).strftime(self.send("#{attribute_name}"))
78
+ else
79
+ DateAsString::Formats.find_format(options[:default_display_format]).strftime(self.send("#{attribute_name}"))
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ define_method "#{attribute_name}_string=" do |str|
86
+ instance_variable_set("@#{attribute_name}_string", str)
87
+ self.send("#{attribute_name}=", DateAsString.parse_string(str))
88
+ end
89
+
90
+ define_method "#{attribute_name}_format" do
91
+ re = /^(([tT]([\-\+]\d+)?)|(\d{6})|(\d{8})|([0-1]?\d\/[0-3]?\d\/\d\d)|([0-1]?\d\/[0-3]?\d\/(19|20)\d\d))$/
92
+
93
+ attribute_string = instance_variable_get("@#{attribute_name}_string")
94
+
95
+ #No string was entered - this clears the date
96
+ return if attribute_string.blank?
97
+
98
+ #the entered string did not match a regex...
99
+ if (attribute_string =~ re).nil?
100
+ errors.add("#{attribute_name}_string", "must be in the format of MM/DD/YY, MM/DD/YYYY, MMDDYY, MMDDYYYY or t, t+#, t-#")
101
+ return
102
+ end
103
+
104
+ #The mapping did not work for some reason...
105
+ if self.send("#{attribute_name}").nil?
106
+ errors.add("#{attribute_name}_string", :invalid)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ def self.year_range(cutoff)
116
+ current_year = Time&.zone&.today&.year || Date.today.year
117
+
118
+ range_start = current_year - (99 - cutoff)
119
+ range_end = current_year + cutoff
120
+
121
+ range_start..range_end
122
+ end
123
+
124
+ def self.get_century_from_year_range(year, cutoff=20)
125
+ year_range(cutoff).detect { |temp_year| temp_year % 100 == year }
126
+ end
127
+
128
+ def self.raise_century_error
129
+ raise RangeError.new('Error converting year...')
130
+ end
131
+
132
+ def self.t_regex
133
+ /^[tT]((?<operator>[\-\+])(?<days_count>\d+))?$/
134
+ end
135
+
136
+ #Allow MMDDYY or MM/DD/YY
137
+ def self.mmddyy_regex(options={})
138
+ with_slashes = options.fetch(:with_slashes, false)
139
+
140
+ slash_str = with_slashes ? '/' : nil
141
+ month_str = '(?<month>[0-1]?\d)'
142
+ day_str = '(?<day>[0-3]?\d)'
143
+ year_str = '(?<year>\d{2})'
144
+
145
+ date_tup = [month_str, day_str, year_str]
146
+ slashes = [slash_str]*2
147
+
148
+ inner_regex = date_tup.zip(slashes)
149
+ .flatten
150
+ .compact
151
+ .join
152
+
153
+ /^#{inner_regex}$/
154
+ end
155
+
156
+ #Allow MMDDYYYY or MM/DD/YYYY
157
+ def self.mmddyyyy_regex(options={})
158
+ with_slashes = options.fetch(:with_slashes, false)
159
+
160
+ slash_str = with_slashes ? '/' : nil
161
+ month_str = '(?<month>[0-1]?\d)'
162
+ day_str = '(?<day>[0-3]?\d)'
163
+ year_str = '(?<year>\d{4})'
164
+
165
+ date_tup = [month_str, day_str, year_str]
166
+ slashes = [slash_str]*2
167
+
168
+ inner_regex = date_tup.zip(slashes)
169
+ .flatten
170
+ .compact
171
+ .join
172
+
173
+ /^#{inner_regex}$/
174
+ end
175
+
176
+ # matches:
177
+ # e.g.)
178
+ # t => Date.today
179
+ # t+7 => Date.today + 1.week
180
+ # t-1 => Date.today - 1.day
181
+ def self.date_for_t_match(date_string)
182
+ today = Time&.zone&.today || Date.today
183
+
184
+ t_regex.match(date_string) do |match_data|
185
+ operator, days_count = *[match_data[:operator], match_data[:days_count]]
186
+
187
+ operator ? today.send(operator, days_count.to_i) : today
188
+ end
189
+ end
190
+
191
+ def self.date_for_mmddyy_match(date_string, options={})
192
+ slashy_regex = options.fetch(:with_slashes, false)
193
+ month, day, year = nil, nil, nil
194
+
195
+ mmddyy_regex(with_slashes: slashy_regex).match(date_string) do |match_data|
196
+ month = match_data[:month] ? match_data[:month] : date_string[0..1]
197
+ day = match_data[:day] ? match_data[:day] : date_string[2..3]
198
+ year = match_data[:year] ? match_data[:year] : date_string[4..5]
199
+
200
+ century = DateAsString.guess_century(year.to_i)
201
+
202
+ Date.civil(century, month.to_i, day.to_i)
203
+ end
204
+ end
205
+
206
+ def self.date_for_mmddyyyy_match(date_string, options={})
207
+ slashy_regex = options.fetch(:with_slashes, false)
208
+ month, day, year = nil, nil, nil
209
+
210
+ mmddyyyy_regex(with_slashes: slashy_regex).match(date_string) do |match_data|
211
+ month = match_data[:month] ? match_data[:month] : date_string[0..1]
212
+ day = match_data[:day] ? match_data[:day] : date_string[2..3]
213
+ year = match_data[:year] ? match_data[:year] : date_string[4..5]
214
+
215
+ Date.civil(year.to_i, month.to_i, day.to_i)
216
+ end
217
+ end
218
+ end
219
+
220
+ if Object.const_defined?("ActiveRecord")
221
+ ActiveRecord::Base.send(:include, DateAsString)
222
+ end
@@ -0,0 +1,55 @@
1
+ module DateAsString
2
+ module Formats
3
+ def self.find_format(format_string)
4
+ case format_string
5
+ when :mm_dd_yyyy
6
+ Format1
7
+ when :mm_dd_yy
8
+ Format2
9
+ when :mmddyyyy
10
+ Format3
11
+ when :mmddyy
12
+ Format4
13
+ when :t_pmd
14
+ Format5
15
+ else
16
+ raise TypeError.new("Format does not exist: #{format_string}")
17
+ end
18
+ end
19
+
20
+ #mm_dd_yyyy
21
+ class Format1
22
+ def self.strftime(value)
23
+ value.strftime('%m/%d/%Y')
24
+ end
25
+ end
26
+
27
+ #mm_dd_yy
28
+ class Format2
29
+ def self.strftime(value)
30
+ value.strftime('%m/%d/%y')
31
+ end
32
+ end
33
+
34
+ #mmddyyyy
35
+ class Format3
36
+ def self.strftime(value)
37
+ value.strftime('%m%d%Y')
38
+ end
39
+ end
40
+
41
+ #mmddyy
42
+ class Format4
43
+ def self.strftime(value)
44
+ value.strftime('%m%d%y')
45
+ end
46
+ end
47
+
48
+ #t_pmd
49
+ class Format5
50
+ def self.strftime(value)
51
+ raise NotImplementedError.new
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,12 @@
1
+ module DateAsString
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 6
6
+ PRE = nil
7
+
8
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
+
10
+ SUMMARY = "date_as_string #{STRING}"
11
+ end
12
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'DateAsString' do
4
+ let(:today) { Date.today }
5
+ let(:tomorrow) { today + 1.day }
6
+ let(:yesterday) { today - 1.day }
7
+ let(:new_years_day_1990) { Date.new(1990, 1, 1) }
8
+
9
+ describe '.parse_date(date)' do
10
+ subject { DateAsString.parse_date date_arg }
11
+
12
+ context 'when provided with a Date' do
13
+ let(:date_arg) { new_years_day_1990 }
14
+
15
+ it { is_expected.to eq "01/01/1990" }
16
+ end
17
+
18
+ describe 'handling invalid arguments' do
19
+ context "argument is a String" do
20
+ let(:date_arg) { 'abc' }
21
+
22
+ it { is_expected.to eq nil }
23
+ end
24
+ end
25
+ end
26
+
27
+ describe ".parse_string(string)" do
28
+ subject { DateAsString.parse_string date_string_arg }
29
+
30
+ context "format -> 't+#'" do
31
+ let(:date_string_arg) { "t+1" }
32
+
33
+ it { is_expected.to eq tomorrow }
34
+ end
35
+
36
+ context "format -> 't-#'" do
37
+ let(:date_string_arg) { "t-1" }
38
+
39
+ it { is_expected.to eq yesterday }
40
+ end
41
+
42
+ context "format -> 't'" do
43
+ let(:date_string_arg) { "t" }
44
+
45
+ it { is_expected.to eq today }
46
+ end
47
+
48
+ context "format -> '######'" do
49
+ let(:date_string_arg) { "010190" }
50
+
51
+ it { is_expected.to eq new_years_day_1990 }
52
+ end
53
+
54
+ context "format -> '########'" do
55
+ let(:date_string_arg) { "01011990" }
56
+
57
+ it { is_expected.to eq new_years_day_1990 }
58
+ end
59
+
60
+ context "format -> '##/##/##'" do
61
+ let(:date_string_arg) { "01/01/90" }
62
+
63
+ it { is_expected.to eq new_years_day_1990 }
64
+ end
65
+
66
+ context "format -> '##/##/####'" do
67
+ let(:date_string_arg) { "01/01/1990" }
68
+
69
+ it { is_expected.to eq new_years_day_1990 }
70
+ end
71
+
72
+ describe 'handling invalid arguments' do
73
+ context "argument is a String" do
74
+ let(:date_string_arg) { 'abc' }
75
+
76
+ it { is_expected.to eq nil }
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,15 @@
1
+ require "date_as_string/version"
2
+ require "date_as_string/formats"
3
+
4
+ require 'active_support/all'
5
+
6
+ require 'bundler/setup'
7
+ Bundler.setup
8
+
9
+ require 'date_as_string'
10
+
11
+ require 'byebug'
12
+
13
+ RSpec.configure do |config|
14
+ # some (optional) config here
15
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: date_as_string
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Eric Sullivan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Treat an ActiveRecord Date column as a String
28
+ email:
29
+ - eric.sullivan@annkissam.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - Gemfile
37
+ - Rakefile
38
+ - date_as_string.gemspec
39
+ - lib/date_as_string.rb
40
+ - lib/date_as_string/formats.rb
41
+ - lib/date_as_string/version.rb
42
+ - spec/date_as_string_spec.rb
43
+ - spec/spec_helper.rb
44
+ homepage: http://annkissam.com
45
+ licenses: []
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project: date_as_string
63
+ rubygems_version: 2.7.6
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: Convert from Date to String and vice versa by attaching _string suffix to
67
+ an ActiveRecord field
68
+ test_files: []