diff --git a/README.md b/README.md index efbfb8c..625610a 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,25 @@ Use `:array` style for structured data: => ["5 months", "1 week"] ``` +#### `only` + +Use the `only` option to accumulate all time into a single unit. Supported values are `:years`, `:months`, `:weeks`, and `:days`: + +```ruby +>> timeago(Date.today.prev_day(365), only: :weeks) +=> "52 weeks ago" +>> timeago(Date.today.prev_day(365), only: :months) +=> "12 months ago" +>> timeago(Date.today.prev_day(100), only: :weeks) +=> "14 weeks ago" +>> timeago(Date.today.prev_day(500), only: :days) +=> "500 days ago" +>> timeago(Date.today.prev_day(365), only: :weeks, style: :short) +=> "52w ago" +>> timeago(Date.today.prev_day(365), only: :months, locale: :es) +=> "hace 12 meses" +``` + ## Localization By default, `jekyll-timego` already provides translations for some languages. You can check the list [here](lib/locales/). However, you are able to provide your own translations, or even override the originals, easily. @@ -169,6 +188,10 @@ il y a environ 2 années et 6 mois 2y ago > timeago 2016-1-1 2018-1-1 -l es -s short hace 2a y 1d +> timeago 2016-1-1 2018-1-1 --only weeks +104 weeks ago +> timeago 2016-1-1 2018-1-1 --only months -s short +24mo ago ``` ### Console diff --git a/bin/timeago b/bin/timeago index 45761da..f8bf150 100755 --- a/bin/timeago +++ b/bin/timeago @@ -39,6 +39,10 @@ parser = OptionParser.new do |opts| opts.on("-s", "--style STYLE", "Uses the provided style (short, array)") do |style| options[:style] = style end + + opts.on("-o", "--only UNIT", "Accumulates time in specified unit (years, months, weeks, days)") do |unit| + options[:only] = unit + end end begin diff --git a/lib/jekyll-timeago/core.rb b/lib/jekyll-timeago/core.rb index 3c6aff8..c5d392f 100644 --- a/lib/jekyll-timeago/core.rb +++ b/lib/jekyll-timeago/core.rb @@ -17,6 +17,9 @@ module Core # Available styles STYLES = %w(default short array) + # Available "only" options + ONLY_OPTIONS = %w(years months weeks days) + def timeago(from, to = Date.today, options = {}) if to.is_a?(Hash) options = to @@ -30,6 +33,7 @@ def timeago(from, to = Date.today, options = {}) @depth = validate_depth(@options[:depth] || @options["depth"]) @style = validate_style(@options[:style] || @options["style"]) @threshold = validate_threshold(@options[:threshold] || @options["threshold"]) + @only = validate_only(@options[:only] || @options["only"]) time_ago_to_now end @@ -53,6 +57,12 @@ def validate_style(style) STYLES.include?(style) ? style : nil end + def validate_only(only) + return nil if only.nil? + only = only.to_s + ONLY_OPTIONS.include?(only) ? only : nil + end + def time_ago_to_now days_passed = (@to - @from).to_i @@ -85,6 +95,9 @@ def translate_unit(unit, count) # Builds time ranges with natural unit conversions: ['1 month', '5 days'] def build_time_ago_slots(days_passed) + # If "only" option is specified, calculate total time in that unit + return build_only_slots(days_passed) if @only + # Calculate components with natural unit conversions components = calculate_natural_components(days_passed) @@ -95,6 +108,33 @@ def build_time_ago_slots(days_passed) selected.map { |unit, count| translate_unit(unit, count) } end + # Build time slots when "only" option is specified + def build_only_slots(days_passed) + unit = @only.to_sym + count = calculate_total_in_unit(days_passed, unit) + [translate_unit(unit, count)] + end + + # Calculate total time in specified unit + def calculate_total_in_unit(days_passed, unit) + case unit + when :days + days_passed + when :weeks + # Ensure minimum of 1 week if days_passed > 0 + return 1 if days_passed > 0 && days_passed < 7 + (days_passed / 7.0).round + when :months + # Ensure minimum of 1 month if days_passed > 0 + return 1 if days_passed > 0 && days_passed < 30 + (days_passed / 30.0).round + when :years + # Ensure minimum of 1 year if days_passed > 0 + return 1 if days_passed > 0 && days_passed < 365 + (days_passed / 365.0).round + end + end + def calculate_natural_components(days_passed) years = days_passed / 365 remaining_days = days_passed % 365 diff --git a/spec/jekyll-timeago_spec.rb b/spec/jekyll-timeago_spec.rb index 639f0c3..7ae20f3 100644 --- a/spec/jekyll-timeago_spec.rb +++ b/spec/jekyll-timeago_spec.rb @@ -130,6 +130,44 @@ expect(timeago(sample_date.prev_day(160), sample_date, style: :array)).to eq(['5 months', '1 week']) expect(timeago(sample_date.prev_day(160), sample_date, style: :array, locale: :es)).to eq(['5 meses', '1 semana']) end + + it 'allows "only" option to accumulate time into single unit' do + # Test "only: :days" + expect(timeago(sample_date.prev_day(7), sample_date, only: :days)).to eq('7 days ago') + expect(timeago(sample_date.prev_day(7), sample_date, "only" => "days")).to eq('7 days ago') + expect(timeago(sample_date.prev_day(30), sample_date, only: :days)).to eq('30 days ago') + + # Test "only: :weeks" + expect(timeago(sample_date.prev_day(7), sample_date, only: :weeks)).to eq('1 week ago') + expect(timeago(sample_date.prev_day(14), sample_date, only: :weeks)).to eq('2 weeks ago') + expect(timeago(sample_date.prev_day(30), sample_date, only: :weeks)).to eq('4 weeks ago') + expect(timeago(sample_date.prev_day(365), sample_date, only: :weeks)).to eq('52 weeks ago') + + # Test "only: :months" + expect(timeago(sample_date.prev_day(30), sample_date, only: :months)).to eq('1 month ago') + expect(timeago(sample_date.prev_day(60), sample_date, only: :months)).to eq('2 months ago') + expect(timeago(sample_date.prev_day(365), sample_date, only: :months)).to eq('12 months ago') + + # Test "only: :years" + expect(timeago(sample_date.prev_day(365), sample_date, only: :years)).to eq('1 year ago') + expect(timeago(sample_date.prev_day(730), sample_date, only: :years)).to eq('2 years ago') + expect(timeago(sample_date.prev_day(1000), sample_date, only: :years)).to eq('3 years ago') + end + + it 'allows "only" option with different styles' do + # Test with short style + expect(timeago(sample_date.prev_day(365), sample_date, only: :weeks, style: :short)).to eq('52w ago') + expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :short)).to eq('1mo ago') + + # Test with array style + expect(timeago(sample_date.prev_day(365), sample_date, only: :weeks, style: :array)).to eq(['52 weeks']) + expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :array)).to eq(['1 month']) + end + + it 'allows "only" option with different locales' do + expect(timeago(sample_date.prev_day(30), sample_date, only: :weeks, locale: :es)).to eq('hace 4 semanas') + expect(timeago(sample_date.prev_day(365), sample_date, only: :months, locale: :fr)).to eq('il y a environ 12 mois') + end end context 'CLI' do @@ -161,11 +199,16 @@ expect(`bin/timeago 2016-1-1 2018-1-1 -s short`).to match("2y and 1d ago") expect(`bin/timeago 2016-1-1 2018-1-1 --style short`).to match("2y and 1d ago") expect(`bin/timeago 2016-1-1 2016-2-1 -s short`).to match("1mo and 1d ago") - end - - it 'with combined locale and style options' do expect(`bin/timeago 2016-1-1 2018-1-1 -l fr -s short`).to match("il y a environ 2a") expect(`bin/timeago 2016-1-1 2018-1-1 --locale ru --style short`).to match("2г и 1д назад") end + + it 'with only option' do + expect(`bin/timeago 2016-1-1 2018-1-1 --only weeks`).to match("104 weeks ago") + expect(`bin/timeago 2016-1-1 2018-1-1 -o months`).to match("24 months ago") + expect(`bin/timeago 2016-1-1 2016-2-1 --only days`).to match("31 days ago") + expect(`bin/timeago 2016-1-1 2018-1-1 -l fr --only months`).to match("il y a environ 24 mois") + expect(`bin/timeago 2016-1-1 2018-1-1 --only weeks -s short`).to match("104w ago") + end end end