merch_calendar 0.1.0 → 0.3.0

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: c82e19a6628132edf5ef227e08d270fc8e1aa3ef
4
- data.tar.gz: 6bcc92b82007ee4cf137435092ac7df7f6f24a33
3
+ metadata.gz: 13a41aecf0152a0c3bffeed5ecf51f15dd5d6927
4
+ data.tar.gz: 482637d57739642817b9c8729f6598fdd4ba4ff7
5
5
  SHA512:
6
- metadata.gz: a532b4acdd1a97639b1894b53181279f750531fd5ac99b2d5f95d40f9cc5330a26b17f8eb85e5304f8a9477596378c22db4355c0f6f39b6766c93730c5e945fd
7
- data.tar.gz: 6360b4c0c3c20d6565dae5fc83f2e089c50f6b0fa159a9af99211363316bd3be8bebe5075c5a0bb79253d22a85cd63e53f6dd9e9979c22d6c495569429e8967a
6
+ metadata.gz: cee1f7ae6cf8817c0616eb46eb572f3a39cf6deb087ed6515335ad693030ae5106353915199be23b471d53e494a7f190ba7ccf021523c66674fd96e52ac71085
7
+ data.tar.gz: c49c4924295a06b57a71c164a2f6c57a6b433ef25b0eb3359e42da3cec27f8b3f25affc94009c57337cf4d872747deddff78585a4a95c65e57b3093aa7bd6e03
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
1
  source 'https://www.rubygems.org'
2
2
 
3
- gemspec
3
+ gemspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- merch_calendar (0.1.0)
4
+ merch_calendar (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://www.rubygems.org/
@@ -58,4 +58,4 @@ DEPENDENCIES
58
58
  simplecov
59
59
 
60
60
  BUNDLED WITH
61
- 1.15.1
61
+ 1.15.3
data/README.md CHANGED
@@ -24,13 +24,13 @@ gem "merch_calendar"
24
24
  For converting a date into a `MerchWeek` object.
25
25
 
26
26
  ```ruby
27
- merch_week = MerchCalendar::MerchWeek.from_date("2014-01-01")
27
+ merch_week = MerchCalendar::MerchWeek.from_date("2014-01-01", calendar: MerchCalendar::RetailCalendar.new)
28
28
 
29
29
  merch_week.year # 2013 (the merch year associated with this date)
30
30
  merch_week.month # 12 (the julian month that the date falls in)
31
31
  merch_week.week # 5 (the week number within the month)
32
- merch_week.year_week # 48 (the week number within the year)
33
- merch_week.quarter # 2
32
+ merch_week.year_week # 48 (the week number within the retail calendar year)
33
+ merch_week.quarter # 4
34
34
 
35
35
  merch_week.start_of_week # <Date: 2013-12-29>
36
36
  merch_week.end_of_week # <Date: 2014-01-04>
@@ -41,6 +41,9 @@ merch_week.end_of_month # <Date: 2014-01-04>
41
41
  merch_week.start_of_year # <Date: 2013-02-03>
42
42
  merch_week.end_of_year # <Date: 2014-02-01>
43
43
 
44
+ merch_week.calendar # <MerchCalendar::RetailCalendar> (the calendar we're using)
45
+ # if you don't initialize a calendar, it defaults to RetailCalendar
46
+
44
47
  # Formatting
45
48
  merch_week.to_s # "Dec W5"
46
49
  merch_week.to_s(:short) # "Dec W5"
@@ -51,7 +54,7 @@ merch_week.to_s(:elasticsearch) # "2013-12w05"
51
54
 
52
55
  ### Merch retail calendar
53
56
 
54
- Merch calendars have their first month in February, and the last (12th) month is in January of the
57
+ Retail calendars have their first month in February, and the last (12th) month is in January of the
55
58
  following year.
56
59
 
57
60
  ```ruby
@@ -102,18 +105,17 @@ retail_calendar.end_of_week(2017, 4, 1)
102
105
  #=> #<Date: 2017-05-06 ((2457880j,0s,0n),+0s,2299161j)>
103
106
  ```
104
107
 
105
- ### Offset fiscal year calendars
106
- Some companies, one of which being Stitch Fix, operate on a fiscal year calendar that is offset from
107
- the traditional retail calendar. The `MerchCalendar::FiscalYearCalendar` class allows you to easily
108
- offset the start of year to match your fiscal calendar.
108
+ ### Stitch Fix Fiscal Year Calendars
109
+ Some companies, one of which being Stitch Fix, operate on a fiscal year calendar that instead starts in August
110
+ rather than in February in a the traditional retail calendar. The `MerchCalendar::StitchFixFiscalYearCalendar` class
111
+ allows you to easily translate Gregorian dates to a Stitch Fix Fiscal Year date.
109
112
 
110
113
  ```ruby
111
- fiscal_calendar = MerchCalendar::FiscalYearCalendar.new
114
+ fiscal_calendar = MerchCalendar::StitchFixFiscalYearCalendar.new
112
115
 
113
- # 52 or 53 (depending on leap year)
114
- fiscal_calendar.weeks_in_year(2017)
115
- # => 52
116
116
  fiscal_calendar.weeks_in_year(2018)
117
+ # => 52
118
+ fiscal_calendar.weeks_in_year(2019)
117
119
  # => 53
118
120
 
119
121
  # get the start date of a given merch week
@@ -125,6 +127,39 @@ fiscal_calendar.end_of_week(2017, 4, 1)
125
127
  #=> #<Date: 2017-05-06 ((2457880j,0s,0n),+0s,2299161j)>
126
128
  ```
127
129
 
130
+ #### Stitch Fix Fiscal Year Calendar in Relation to MerchWeek object
131
+ You can set MerchWeek object respond to the Stitch Fix Fiscal Calendar, by passing in `StitchFixFiscalYearCalendar.new` in the calendar parameter:
132
+
133
+ ```ruby
134
+ merch_week = MerchCalendar::MerchWeek.from_date("2018-07-02", calendar: MerchCalendar::StitchFixFiscalYearCalendar.new)
135
+
136
+ merch_week.year # 2018 (the merch year associated with this date)
137
+ merch_week.month # 7 (the julian month that the date falls in)
138
+ merch_week.merch_month # 12 (this fiscal month the date falls in)
139
+ merch_week.week # 1 (the week number within the month)
140
+ merch_week.year_week # 49 (the week number within the retail calendar year)
141
+ merch_week.quarter # 4
142
+
143
+ merch_week.start_of_week # <Date: 2018-07-01>
144
+ merch_week.end_of_week # <Date: 2018-07-07>
145
+
146
+ merch_week.start_of_month # <Date: 2018-07-01>
147
+ merch_week.end_of_month # <Date: 2018-07-28>
148
+
149
+ merch_week.start_of_year # <Date: 2017-07-30>
150
+ merch_week.end_of_year # <Date: 2018-07-28>
151
+
152
+ merch_week.calendar # <MerchCalendar::StitchFixFiscalYearCalendar> (the calendar
153
+ # we're using)
154
+ # if you don't initialize a calendar, it defaults to RetailCalendar
155
+
156
+ # Formatting
157
+ merch_week.to_s # "Jul W1"
158
+ merch_week.to_s(:short) # "Jul W1"
159
+ merch_week.to_s(:long) # "2018:49 Jul W1"
160
+ merch_week.to_s(:elasticsearch) # "2018-07w01"
161
+ ```
162
+
128
163
  ## Documentation
129
164
  You can view the documentation for this gem on [RubyDoc.info](http://www.rubydoc.info/github/stitchfix/merch_calendar/master).
130
165
 
@@ -1,6 +1,6 @@
1
1
  module MerchCalendar
2
2
 
3
- # Represents the Merch Week for a specified date.
3
+ # Represents the Merch Week for a specified date and calendar
4
4
  class MerchWeek
5
5
 
6
6
  MONTHS = %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec).freeze
@@ -10,56 +10,68 @@ module MerchCalendar
10
10
  # @!attribute [r] date
11
11
  # @return [Date] the date for this merch week
12
12
  attr_reader :date
13
-
14
- class << self
15
-
16
- # Locates the +MerchWeek+ for a given Julian date.
17
- #
18
- # @overload from_date(String)
19
- # @param [String] julian_date a julian date in the format of +YYYY-MM-DD+
20
- # @overload from_date(Date)
21
- # @param [Date] julian_date a +Date+ object
22
- #
23
- # @return [MerchWeek]
24
- def from_date(julian_date)
25
- MerchWeek.new Date.parse("#{julian_date}")
26
- end
27
-
28
- # Returns an array of merch weeks for a month, or a specific week.
29
- #
30
- # @overload find(year, julian_month)
31
- # Returns an array of +MerchWeek+s for a given month
32
- # @param year [Fixnum] the merch year to locate
33
- # @param julian_month [Fixnum] the month to find merch months for
34
- # @return [Array<MerchWeek>]
35
- # @overload find(year, julian_month, week_number)
36
- # @param year [Fixnum] the merch year to locate
37
- # @param julian_month [Fixnum] the month to find merch months for
38
- # @param week_number [Fixnum] the specific week number.
39
- # @return [MerchWeek] the specific merch week
40
- def find(year, julian_month, week_number=nil)
41
- if week_number.nil?
42
- MerchCalendar.weeks_for_month(year, julian_month)
43
- else
44
- MerchCalendar.weeks_for_month(year, julian_month)[week_number-1]
45
- end
46
- end
47
-
48
- # Returns the +MerchWeek+ for today's date
49
- #
50
- # @return [MerchWeek]
51
- def today
52
- MerchWeek.from_date Date.today
13
+
14
+ # The Merch Calendar that is being represented, either Fiscal or Retail
15
+ #
16
+ # @!attribute [r] calendar
17
+ # @return [Class] the calendar that determines the merch week
18
+ attr_reader :calendar
19
+
20
+ # Locates the +MerchWeek+ for a given Julian date.
21
+ #
22
+ # @overload from_date(String)
23
+ # @param julian_date [String] a julian date in the format of +YYYY-MM-DD+
24
+ # @param options [Hash] opts the options to set your calendar, if none it will default to RetailCalendar
25
+ # # @option opts [Class] :calendar The Calendar Class
26
+ # @overload from_date(Date)
27
+ # @param julian_date [Date] julian_date a +Date+ object
28
+ # @param options [Hash] opts the options to set your calendar, if none it will default to RetailCalendar
29
+ # # @option opts [Class] :calendar The Calendar Class
30
+ # @return [MerchWeek]
31
+ def self.from_date(julian_date, options = {})
32
+ MerchWeek.new(Date.parse("#{julian_date}"), options)
33
+ end
34
+
35
+ # Returns an array of merch weeks for a month, or a specific week.
36
+ #
37
+ # @overload find(year, julian_month, week_number=nil, options)
38
+ # Returns an array of +MerchWeek+s for a given month
39
+ # @param year [Fixnum] the merch year to locate
40
+ # @param julian_month [Fixnum] the month to find merch months for
41
+ # @param week_number [Nil] set week_number to nil
42
+ # @param options [Hash] options to set your calendar, if none it will default to RetailCalendar
43
+ # @return [Array<MerchWeek>]
44
+ # @overload find(year, julian_month, week_number)
45
+ # @param year [Fixnum] the merch year to locate
46
+ # @param julian_month [Fixnum] the month to find merch months for
47
+ # @param week_number [Fixnum] the specific week number.
48
+ # @param options [Hash] options to set your calendar, if none it will default to RetailCalendar
49
+ # @return [MerchWeek] the specific merch week based on the week number
50
+ def self.find(year, julian_month, week_number=nil, options={})
51
+ calendar = options.fetch(:calendar, RetailCalendar.new)
52
+ if week_number.nil?
53
+ calendar.weeks_for_month(year, julian_month)
54
+ else
55
+ calendar.weeks_for_month(year, julian_month)[week_number-1]
53
56
  end
54
57
  end
55
58
 
56
-
59
+ # Returns the +MerchWeek+ for today's date
60
+ #
61
+ # @param options [Hash] opts the options to set your calendar, if none it will default to RetailCalendar
62
+ # # @option opts [Class] :calendar The Calendar Class
63
+ # @return [MerchWeek]
64
+ def self.today(options={})
65
+ MerchWeek.from_date(Date.today, options)
66
+ end
57
67
 
58
68
  # Pass in a date, make sure it is a valid date object
59
69
  # @private
60
70
  def initialize(date, options = {})
61
71
  @date = date
62
-
72
+
73
+ #defaults to Retail Calendar if no other calendar is defined
74
+ @calendar = options.fetch(:calendar, RetailCalendar.new)
63
75
  # Placeholders. These should be populated by functions if nil
64
76
  # week_start: nil, week_end: nil, week_number: nil
65
77
  @start_of_year = options[:start_of_year]
@@ -81,62 +93,55 @@ module MerchCalendar
81
93
  end
82
94
 
83
95
  # This returns the "merch month" number for a date
84
- # Merch months are shifted by one. Month 1 is Feb
96
+ # Month 1 is Feb for the retail calendar
97
+ # Month 1 is August for the fiscal calendar
85
98
  #
86
99
  # @return [Fixnum]
87
100
  def merch_month
88
101
  # TODO: This is very inefficient, but less complex than strategic guessing
89
102
  # maybe switch to a binary search or something
103
+ merch_year = calendar.merch_year_from_date(date)
90
104
  @merch_month ||= (1..12).detect do |num|
91
- retail_calendar.end_of_month(start_of_year.year, num) >= date && date >= retail_calendar.start_of_month(start_of_year.year, num)
105
+ calendar.end_of_month(merch_year, num) >= date && date >= calendar.start_of_month(merch_year, num)
92
106
  end
93
107
  end
94
108
 
95
- # The merch year
109
+ # Returns the Merch year depending whether it is from the Retail or Fiscal calendar
96
110
  #
97
111
  # @return [Fixnum]
98
112
  def year
99
- start_of_year.year
113
+ @year ||= calendar.merch_year_from_date(date)
100
114
  end
101
115
 
102
- # The julian month that this merch week falls in
116
+ # Returns julian month where the merch week falls
103
117
  #
104
118
  # @return [Fixnum]
105
119
  def month
106
- @month ||= MerchCalendar.merch_to_julian(merch_month)
120
+ @month ||= calendar.merch_to_julian(merch_month)
107
121
  end
108
122
 
109
- # The specific quarter this week falls in
123
+ # Returns the quarter that this merch week falls
110
124
  #
111
125
  # @return [Fixnum]
112
126
  def quarter
113
- case merch_month
114
- when 7,8,9
115
- return 1
116
- when 10,11,12
117
- return 2
118
- when 1,2,3
119
- return 3
120
- else
121
- return 4
122
- end
127
+ @quarter ||= calendar.quarter(merch_month)
123
128
  end
124
129
 
125
- # Returns the date of the start of this week
130
+ # Returns the start date of this week
126
131
  #
127
132
  # @return [Date]
128
133
  def start_of_week
129
134
  @start_of_week ||= (start_of_month + (7 * (week - 1)))
130
135
  end
131
136
 
132
- # Returns the date of the end of this week
137
+ # Returns the end date of this week
133
138
  #
134
139
  # @return [Date]
135
140
  def end_of_week
136
141
  @end_of_week ||= (start_of_week + 6)
137
142
  end
138
143
 
139
- # the number of the week within the given month
144
+ # The number of the week within the given merch month
140
145
  # will be between 1 and 5
141
146
  #
142
147
  # @return [Fixnum]
@@ -144,32 +149,32 @@ module MerchCalendar
144
149
  @week ||= (((date-start_of_month)+1)/7.0).ceil
145
150
  end
146
151
 
147
- # The date of the start of the corresponding merch year
152
+ # The start date of the corresponding merch year
148
153
  #
149
154
  # @return [Date]
150
155
  def start_of_year
151
- @start_of_year ||= year_start_date
156
+ @start_of_year ||= calendar.start_of_year(year)
152
157
  end
153
158
 
154
159
  # The end date of the corresponding merch year
155
160
  #
156
161
  # @return [Date]
157
162
  def end_of_year
158
- @end_of_year ||= retail_calendar.end_of_year(year)
163
+ @end_of_year ||= calendar.end_of_year(year)
159
164
  end
160
165
 
161
166
  # The start date of the merch month
162
167
  #
163
168
  # @return [Date]
164
169
  def start_of_month
165
- @start_of_month ||= retail_calendar.start_of_month(year, merch_month)
170
+ @start_of_month ||= calendar.start_of_month(year, merch_month)
166
171
  end
167
172
 
168
173
  # The end date of the merch month
169
174
  #
170
175
  # @return [Date]
171
176
  def end_of_month
172
- @end_of_month ||= retail_calendar.end_of_month(year, merch_month)
177
+ @end_of_month ||= calendar.end_of_month(year, merch_month)
173
178
  end
174
179
 
175
180
  # The merch season this date falls under.
@@ -177,12 +182,7 @@ module MerchCalendar
177
182
  #
178
183
  # @return [String]
179
184
  def season
180
- case merch_month
181
- when 1,2,3,4,5,6
182
- "Spring/Summer"
183
- when 7,8,9,10,11,12
184
- "Fall/Winter"
185
- end
185
+ @season ||= calendar.season(merch_month)
186
186
  end
187
187
 
188
188
  # Outputs a text representation of this merch week
@@ -193,7 +193,6 @@ module MerchCalendar
193
193
  # * +:elasticsearch+ (default) "2012-12w05"
194
194
  #
195
195
  # @param format [Symbol] the format identifier to return. Default is +:short+
196
- #
197
196
  # @return [Date]
198
197
  def to_s(format = :short)
199
198
  case format
@@ -205,20 +204,5 @@ module MerchCalendar
205
204
  "#{MONTHS[month - 1]} W#{week}"
206
205
  end
207
206
  end
208
-
209
- private
210
-
211
- def year_start_date
212
- start_date = retail_calendar.start_of_year(date.year)
213
- if start_date > date
214
- start_date = retail_calendar.start_of_year(date.year - 1)
215
- end
216
- start_date
217
- end
218
-
219
- def retail_calendar
220
- @retail_calendar ||= RetailCalendar.new
221
- end
222
-
223
207
  end
224
208
  end