jekyll-timeago 0.5.2 → 0.7.0
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.
- data/README.md +53 -39
- data/_config.yml.example +1 -0
- data/jekyll-timeago.gemspec +1 -1
- data/lib/jekyll-timeago/filter.rb +140 -0
- data/lib/jekyll-timeago/tag.rb +24 -0
- data/lib/{jekyll/timeago → jekyll-timeago}/version.rb +1 -1
- data/lib/jekyll-timeago.rb +3 -0
- data/script/console +13 -0
- metadata +7 -4
- data/lib/jekyll/timeago.rb +0 -142
data/README.md
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
Jekyll-Timeago
|
2
|
-
==============
|
1
|
+
# Jekyll-Timeago
|
3
2
|
|
4
3
|
[](http://badge.fury.io/rb/jekyll-timeago)
|
5
4
|
|
6
5
|
Custom and simple implementation of `timeago` date filter. Main features:
|
7
6
|
|
8
|
-
*
|
7
|
+
* Distance of dates in words
|
9
8
|
* Future time
|
9
|
+
* Usage via Filter or Tag
|
10
|
+
* Localization
|
10
11
|
* Level of detail
|
11
12
|
|
12
|
-
In fact, `jekyll-timeago` is an extension of [Liquid](https://github.com/Shopify/liquid)
|
13
|
+
In fact, `jekyll-timeago` is an extension of [Liquid](https://github.com/Shopify/liquid) Filters and Tags, so you can use it in other Liquid templates (like Octopress).
|
13
14
|
|
14
15
|
|
15
16
|
## Installation
|
16
|
-
|
17
|
-
You have 3 options for installing the plugin:
|
17
|
+
You have 3 options to install the plugin:
|
18
18
|
|
19
19
|
**Via Jekyll plugin system**
|
20
20
|
|
@@ -27,7 +27,7 @@ gem install jekyll-timeago
|
|
27
27
|
In your `_config.yml` file, add a new array with the key gems and the values of the gem names of the plugins you’d like to use. In this case:
|
28
28
|
|
29
29
|
```
|
30
|
-
gems: [jekyll
|
30
|
+
gems: [jekyll-timeago]
|
31
31
|
```
|
32
32
|
|
33
33
|
**Via Bundler**
|
@@ -38,18 +38,24 @@ Add this gem to your `Gemfile` and run `bundle`:
|
|
38
38
|
gem 'jekyll-timeago'
|
39
39
|
```
|
40
40
|
|
41
|
-
|
41
|
+
Then load the plugin adding the following into some file under `_plugins/` folder:
|
42
42
|
|
43
43
|
```ruby
|
44
|
-
|
44
|
+
# _plugins/ext.rb
|
45
|
+
require 'rubygems'
|
46
|
+
require 'bundler/setup'
|
47
|
+
Bundler.require(:default)
|
45
48
|
```
|
46
49
|
|
47
50
|
**Manually**
|
48
51
|
|
49
|
-
Alternatively, you can simply copy [this file](
|
52
|
+
Alternatively, you can simply copy [this file](lib/jekyll-timeago/filter.rb) and [this file](lib/jekyll-timeago/tag.rb) directly into your `_plugins/` directory!
|
50
53
|
|
51
54
|
|
52
55
|
## Usage
|
56
|
+
By default `timeago` computes distance of dates from passed date to current date (using `Date.today`). But you are able to modify this range passing a second argument in order to compute the distance of these dates in words.
|
57
|
+
|
58
|
+
**Filter example**:
|
53
59
|
|
54
60
|
```html
|
55
61
|
<span>{{ page.date | timeago }}</span>
|
@@ -60,20 +66,31 @@ Alternatively, you can simply copy [this file](https://github.com/markets/jekyll
|
|
60
66
|
</div>
|
61
67
|
```
|
62
68
|
|
63
|
-
|
69
|
+
Passing a parameter:
|
70
|
+
|
71
|
+
```html
|
72
|
+
<span>{{ page.date | timeago: '2020-1-1' }}</span>
|
73
|
+
```
|
74
|
+
|
75
|
+
**Tag example**:
|
76
|
+
|
77
|
+
```html
|
78
|
+
<p>{% timeago 2000-1-1 %}</p>
|
79
|
+
```
|
64
80
|
|
65
|
-
|
81
|
+
Passing a second parameter:
|
66
82
|
|
67
83
|
```html
|
68
|
-
<
|
84
|
+
<p>{% timeago 2000-1-1 20010-1-1 %}</p>
|
69
85
|
```
|
70
86
|
|
71
|
-
## Localization
|
72
87
|
|
73
|
-
|
88
|
+
## Localization
|
89
|
+
The plugin allows you to localize the strings needed to build the time ago sentences. For do this, you must add some extra keys to your `_config.yml`. You can simply copy them from [this example file](_config.yml.example) and translate it to your site's language. Sample:
|
74
90
|
|
75
91
|
```
|
76
92
|
jekyll_timeago:
|
93
|
+
depth: 2 # Level of detail
|
77
94
|
today: 'today'
|
78
95
|
yesterday: 'yesterday'
|
79
96
|
tomorrow: 'tomorrow'
|
@@ -92,42 +109,39 @@ jekyll_timeago:
|
|
92
109
|
day: 'day'
|
93
110
|
```
|
94
111
|
|
95
|
-
## Output Examples
|
96
112
|
|
97
|
-
|
113
|
+
## Level of detail (Depth)
|
114
|
+
You are able to change the level of detail (from 1 up to 4, 2 by default) to get higher or lower granularity. This option is setted via the `config` file (see sample in previous section). Examples:
|
115
|
+
|
116
|
+
* Depht => 1 `1 year ago`
|
117
|
+
* Depht => 2 `1 year and 4 months ago` (default)
|
118
|
+
* Depht => 3 `1 year, 4 months and 1 week ago`
|
119
|
+
* Depht => 4 `1 year, 4 months, 1 week and 4 days ago`
|
120
|
+
|
121
|
+
|
122
|
+
## Output Examples
|
123
|
+
Run `script/console` to start a custom IRB session and play with `timeago` method:
|
98
124
|
|
99
125
|
```ruby
|
100
|
-
|
126
|
+
>> timeago(Date.today)
|
101
127
|
=> "today"
|
102
|
-
|
128
|
+
>> timeago(Date.today - 1.day)
|
103
129
|
=> "yesterday"
|
104
|
-
|
130
|
+
>> timeago(Date.today - 10.days)
|
105
131
|
=> "1 week and 3 days ago"
|
106
|
-
|
132
|
+
>> timeago(Date.today - 100.days)
|
107
133
|
=> "3 months and 1 week ago"
|
108
|
-
|
134
|
+
>> timeago(Date.today - 500.days)
|
109
135
|
=> "1 year and 4 months ago"
|
110
|
-
|
136
|
+
>> timeago('2010-1-1', '2012-1-1')
|
137
|
+
=> "2 years ago"
|
138
|
+
>> timeago(Date.today + 1.days)
|
111
139
|
=> "tomorrow"
|
112
|
-
|
140
|
+
>> timeago(Date.today + 7.days)
|
113
141
|
=> "in 1 week"
|
114
|
-
|
142
|
+
>> timeago(Date.today + 1000.days)
|
115
143
|
=> "in 2 years and 8 months"
|
116
144
|
```
|
117
145
|
|
118
|
-
Change level of detail to get higher or lower granularity:
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
> timeago(Date.today - 500.days) # default
|
122
|
-
=> "1 year and 4 months ago"
|
123
|
-
> timeago(Date.today - 500.days, 3)
|
124
|
-
=> "1 year, 4 months and 1 week ago"
|
125
|
-
> timeago(Date.today - 500.days, 4)
|
126
|
-
=> "1 year, 4 months, 1 week and 4 days ago"
|
127
|
-
> timeago(Date.today - 500.days, 1)
|
128
|
-
=> "1 year ago"
|
129
|
-
```
|
130
|
-
|
131
146
|
## License
|
132
|
-
|
133
147
|
Copyright (c) 2013-2014 Marc Anguera. Jekyll-Timeago is released under the [MIT](LICENSE) License.
|
data/_config.yml.example
CHANGED
data/jekyll-timeago.gemspec
CHANGED
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Timeago
|
5
|
+
module Filter
|
6
|
+
|
7
|
+
DAYS_PER = {
|
8
|
+
:days => 1,
|
9
|
+
:weeks => 7,
|
10
|
+
:months => 30,
|
11
|
+
:years => 365
|
12
|
+
}
|
13
|
+
|
14
|
+
# Max level of detail
|
15
|
+
# years > months > weeks > days
|
16
|
+
# 1 year and 7 months and 2 weeks and 6 days
|
17
|
+
MAX_DEPTH_LEVEL = 4
|
18
|
+
|
19
|
+
# Default level of detail
|
20
|
+
# 1 month and 5 days, 3 weeks and 2 days, 2 years and 6 months
|
21
|
+
DEFAULT_DEPTH_LEVEL = 2
|
22
|
+
|
23
|
+
def timeago(from, to = Date.today)
|
24
|
+
from = validate_date!(from)
|
25
|
+
to = validate_date!(to)
|
26
|
+
depth = validate_depth!(options[:depth])
|
27
|
+
|
28
|
+
time_ago_to_now(from, to, depth)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_date!(date)
|
34
|
+
Date.parse(date.to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_depth!(depth)
|
38
|
+
(1..MAX_DEPTH_LEVEL).include?(depth) or raise("Invalid depth level: #{depth.inspect}")
|
39
|
+
depth
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get plugin configuration from site. Returns an empty hash if not provided.
|
43
|
+
def config
|
44
|
+
@config ||= Jekyll.configuration({}).fetch('jekyll_timeago', {}) rescue {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def options
|
48
|
+
@options ||= {
|
49
|
+
:depth => config['depth'] || DEFAULT_DEPTH_LEVEL,
|
50
|
+
:today => config['day'] || 'today',
|
51
|
+
:yesterday => config['yesterday'] || 'yesterday',
|
52
|
+
:tomorrow => config['tomorrow'] || 'tomorrow',
|
53
|
+
:and => config['and'] ||'and',
|
54
|
+
:suffix => config['suffix'] || 'ago',
|
55
|
+
:prefix => config['prefix'] || '',
|
56
|
+
:suffix_future => config['suffix_future'] || '',
|
57
|
+
:prefix_future => config['prefix_future'] || 'in',
|
58
|
+
:years => config['years'] || 'years',
|
59
|
+
:year => config['year'] || 'year',
|
60
|
+
:months => config['months'] || 'months',
|
61
|
+
:month => config['month'] || 'month',
|
62
|
+
:weeks => config['weeks'] || 'weeks',
|
63
|
+
:week => config['week'] || 'week',
|
64
|
+
:days => config['days'] || 'days',
|
65
|
+
:day => config['day'] || 'day'
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def translate(key)
|
70
|
+
options[key.to_sym]
|
71
|
+
end
|
72
|
+
alias_method :t, :translate
|
73
|
+
|
74
|
+
# Days passed to time ago sentence
|
75
|
+
def time_ago_to_now(from, to, depth)
|
76
|
+
days_passed = (to - from).to_i
|
77
|
+
|
78
|
+
return t(:today) if days_passed == 0
|
79
|
+
return t(:yesterday) if days_passed == 1
|
80
|
+
return t(:tomorrow) if days_passed == -1
|
81
|
+
|
82
|
+
future = days_passed < 0
|
83
|
+
slots = build_time_ago_slots(days_passed.abs, depth)
|
84
|
+
sentence = to_sentence(slots)
|
85
|
+
|
86
|
+
if future
|
87
|
+
"#{t(:prefix_future)} #{sentence} #{t(:suffix_future)}".strip
|
88
|
+
else
|
89
|
+
"#{t(:prefix)} #{sentence} #{t(:suffix)}".strip
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Builds time ranges: ['1 month', '5 days']
|
94
|
+
# - days_passed: integer in absolute
|
95
|
+
# - depth: level of detail
|
96
|
+
# - current_slots: built time slots
|
97
|
+
def build_time_ago_slots(days_passed, depth, current_slots = [])
|
98
|
+
return current_slots if depth == 0 || days_passed == 0
|
99
|
+
|
100
|
+
time_range = days_to_time_range(days_passed)
|
101
|
+
days = DAYS_PER[time_range]
|
102
|
+
num_elems = days_passed / days
|
103
|
+
range_type = if num_elems == 1
|
104
|
+
t(time_range[0...-1]) # singularize key
|
105
|
+
else
|
106
|
+
t(time_range)
|
107
|
+
end
|
108
|
+
|
109
|
+
current_slots << "#{num_elems} #{range_type}"
|
110
|
+
pending_days = days_passed - (num_elems*days)
|
111
|
+
build_time_ago_slots(pending_days, depth - 1, current_slots)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Number of days to minimum period time which can be grouped
|
115
|
+
def days_to_time_range(days_passed)
|
116
|
+
case days_passed.abs
|
117
|
+
when 0...7
|
118
|
+
:days
|
119
|
+
when 7...31
|
120
|
+
:weeks
|
121
|
+
when 31...365
|
122
|
+
:months
|
123
|
+
else
|
124
|
+
:years
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Array to sentence: ['1 month', '1 week', '5 days'] => "1 month, 1 week and 5 days"
|
129
|
+
def to_sentence(slots)
|
130
|
+
if slots.length == 1
|
131
|
+
slots[0]
|
132
|
+
else
|
133
|
+
"#{slots[0...-1].join(', ')} #{t(:and)} #{slots[-1]}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
Liquid::Template.register_filter(Jekyll::Timeago::Filter) if defined?(Liquid)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Timeago
|
3
|
+
class Tag < Liquid::Tag
|
4
|
+
include Jekyll::Timeago::Filter
|
5
|
+
|
6
|
+
def initialize(tag_name, dates, tokens)
|
7
|
+
super
|
8
|
+
@dates = dates.strip.split(' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
from, to = @dates[0], @dates[1]
|
13
|
+
|
14
|
+
if to
|
15
|
+
timeago(from, to)
|
16
|
+
else
|
17
|
+
timeago(from)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Liquid::Template.register_tag('timeago', Jekyll::Timeago::Tag) if defined?(Liquid)
|
data/script/console
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path('../../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'jekyll-timeago/filter'
|
7
|
+
include Jekyll::Timeago::Filter
|
8
|
+
|
9
|
+
require 'active_support/core_ext'
|
10
|
+
|
11
|
+
require 'irb'
|
12
|
+
ARGV.clear
|
13
|
+
IRB.start
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-timeago
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -58,8 +58,11 @@ files:
|
|
58
58
|
- Rakefile
|
59
59
|
- _config.yml.example
|
60
60
|
- jekyll-timeago.gemspec
|
61
|
-
- lib/jekyll
|
62
|
-
- lib/jekyll
|
61
|
+
- lib/jekyll-timeago.rb
|
62
|
+
- lib/jekyll-timeago/filter.rb
|
63
|
+
- lib/jekyll-timeago/tag.rb
|
64
|
+
- lib/jekyll-timeago/version.rb
|
65
|
+
- script/console
|
63
66
|
homepage: https://github.com/markets/jekyll-timeago
|
64
67
|
licenses:
|
65
68
|
- MIT
|
data/lib/jekyll/timeago.rb
DELETED
@@ -1,142 +0,0 @@
|
|
1
|
-
begin; require "jekyll/timeago/version"; rescue LoadError; end
|
2
|
-
|
3
|
-
module Jekyll
|
4
|
-
module Timeago
|
5
|
-
|
6
|
-
DAYS_PER = {
|
7
|
-
:days => 1,
|
8
|
-
:weeks => 7,
|
9
|
-
:months => 30,
|
10
|
-
:years => 365
|
11
|
-
}
|
12
|
-
|
13
|
-
# Max level of detail
|
14
|
-
# years > months > weeks > days
|
15
|
-
# 1 year and 7 months and 2 weeks and 6 days
|
16
|
-
MAX_DEPTH_LEVEL = 4
|
17
|
-
|
18
|
-
# Default level of detail
|
19
|
-
# 1 month and 5 days, 3 weeks and 2 days, 2 years and 6 months
|
20
|
-
DEFAULT_DEPTH_LEVEL = 2
|
21
|
-
|
22
|
-
def timeago(input, depth = DEFAULT_DEPTH_LEVEL)
|
23
|
-
validate!(input, depth)
|
24
|
-
|
25
|
-
time_ago_to_now(input, depth)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
# Validates inputs
|
31
|
-
def validate!(input, depth)
|
32
|
-
unless depth_allowed?(depth)
|
33
|
-
raise "Invalid depth level: #{depth.inspect}"
|
34
|
-
end
|
35
|
-
|
36
|
-
unless input.is_a?(Date) || input.is_a?(Time)
|
37
|
-
raise "Invalid input type: #{input.inspect}"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Get plugin configuration from site. Returns an empty hash if not provided.
|
42
|
-
def config
|
43
|
-
@config ||= Jekyll.configuration({}).fetch('jekyll_timeago', {})
|
44
|
-
end
|
45
|
-
|
46
|
-
def strings
|
47
|
-
{
|
48
|
-
:today => config['day'] || 'today',
|
49
|
-
:yesterday => config['yesterday'] || 'yesterday',
|
50
|
-
:tomorrow => config['tomorrow'] || 'tomorrow',
|
51
|
-
:and => config['and'] ||'and',
|
52
|
-
:suffix => config['suffix'] || 'ago',
|
53
|
-
:prefix => config['prefix'] || '',
|
54
|
-
:suffix_future => config['suffix_future'] || '',
|
55
|
-
:prefix_future => config['prefix_future'] || 'in',
|
56
|
-
:years => config['years'] || 'years',
|
57
|
-
:year => config['year'] || 'year',
|
58
|
-
:months => config['months'] || 'months',
|
59
|
-
:month => config['month'] || 'month',
|
60
|
-
:weeks => config['weeks'] || 'weeks',
|
61
|
-
:week => config['week'] || 'week',
|
62
|
-
:days => config['days'] || 'days',
|
63
|
-
:day => config['day'] || 'day'
|
64
|
-
}
|
65
|
-
end
|
66
|
-
|
67
|
-
def translate(key)
|
68
|
-
strings[key.to_sym]
|
69
|
-
end
|
70
|
-
alias_method :t, :translate
|
71
|
-
|
72
|
-
# Days passed to time ago sentence
|
73
|
-
def time_ago_to_now(input_date, depth)
|
74
|
-
days_passed = (Date.today - Date.parse(input_date.to_s)).to_i
|
75
|
-
|
76
|
-
return t(:today) if days_passed == 0
|
77
|
-
return t(:yesterday) if days_passed == 1
|
78
|
-
return t(:tomorrow) if days_passed == -1
|
79
|
-
|
80
|
-
future = days_passed < 0
|
81
|
-
slots = build_time_ago_slots(days_passed.abs, depth)
|
82
|
-
sentence = to_sentence(slots)
|
83
|
-
|
84
|
-
if future
|
85
|
-
"#{t(:prefix_future)} #{sentence} #{t(:suffix_future)}".strip
|
86
|
-
else
|
87
|
-
"#{t(:prefix)} #{sentence} #{t(:suffix)}".strip
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# Builds time ranges: ['1 month', '5 days']
|
92
|
-
# - days_passed: integer in absolute
|
93
|
-
# - depth: level of detail
|
94
|
-
# - current_slots: built time slots
|
95
|
-
def build_time_ago_slots(days_passed, depth, current_slots = [])
|
96
|
-
return current_slots if depth == 0 || days_passed == 0
|
97
|
-
|
98
|
-
time_range = days_to_time_range(days_passed)
|
99
|
-
days = DAYS_PER[time_range]
|
100
|
-
num_elems = days_passed / days
|
101
|
-
range_type = if num_elems == 1
|
102
|
-
t(time_range[0...-1]) # singularize key
|
103
|
-
else
|
104
|
-
t(time_range)
|
105
|
-
end
|
106
|
-
|
107
|
-
current_slots << "#{num_elems} #{range_type}"
|
108
|
-
pending_days = days_passed - (num_elems*days)
|
109
|
-
build_time_ago_slots(pending_days, depth - 1, current_slots)
|
110
|
-
end
|
111
|
-
|
112
|
-
# Number of days to minimum period time which can be grouped
|
113
|
-
def days_to_time_range(days_passed)
|
114
|
-
case days_passed.abs
|
115
|
-
when 0...7
|
116
|
-
:days
|
117
|
-
when 7...31
|
118
|
-
:weeks
|
119
|
-
when 31...365
|
120
|
-
:months
|
121
|
-
else
|
122
|
-
:years
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# Validate if allowed level of detail
|
127
|
-
def depth_allowed?(depth)
|
128
|
-
(1..MAX_DEPTH_LEVEL).include?(depth)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Array to sentence: ['1 month', '1 week', '5 days'] => "1 month, 1 week and 5 days"
|
132
|
-
def to_sentence(slots)
|
133
|
-
if slots.length == 1
|
134
|
-
slots[0]
|
135
|
-
else
|
136
|
-
"#{slots[0...-1].join(', ')} #{t(:and)} #{slots[-1]}"
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
Liquid::Template.register_filter(Jekyll::Timeago) if defined?(Liquid)
|