timed 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 91f02760afcbcaf91d29ddf7fe817fbc0ec7dcf5
4
+ data.tar.gz: b7220abee0fce727c26f6961ebbffbc737cc7eb2
5
+ SHA512:
6
+ metadata.gz: db98749f2945a92b8ae56e58bdeb08d05c4b417fe8e2d9fc627f9de9cf39becf99000189c9b32b3eda704299eb8ac045ab23ba5f42e96191744534559f828c4d
7
+ data.tar.gz: 076b4b45416d418b1554453f5a97b82c717a242cbff240c827111a527bb0ac24e74b822d03498be917a020f84e035fe4cdec325b8d44b44c8db9e49f96abf97e
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in timed.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Sebastian Lindberg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # Timed
2
+
3
+ [![Build Status](https://travis-ci.org/seblindberg/ruby-timed.svg?branch=master)](https://travis-ci.org/seblindberg/ruby-timed)
4
+ [![Coverage Status](https://coveralls.io/repos/github/seblindberg/ruby-timed/badge.svg?branch=master)](https://coveralls.io/github/seblindberg/ruby-timed?branch=master)
5
+ [![Inline docs](http://inch-ci.org/github/seblindberg/ruby-timed.svg?branch=master)](http://inch-ci.org/github/seblindberg/ruby-timed)
6
+
7
+ Gem for working with timed, ordered items. Still early days.
8
+
9
+ The basic building block is the `Timed::Item`. These begin and end somewhere in time and can thus be related to each other. Several items can then be combined into a `Timed::Sequence`. This object guarantees that the items in it are non overlapping and ordered chronologically.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'timed'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install timed
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ require 'timed'
31
+
32
+ # Create an empty
33
+ sequence = Timed::Sequence.new
34
+
35
+ # Add a couple of items. Any object that implements #begin
36
+ # and #end can be added. Internally it is converted to a
37
+ # Timed::Item.
38
+ sequence << 10..20
39
+ sequence << 30..40
40
+
41
+ # Calculate the time occupied by the items in the sequence
42
+ sequence.time # => 20
43
+ ```
44
+
45
+ ## Development
46
+
47
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
48
+
49
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
50
+
51
+ ## Contributing
52
+
53
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/timed.
54
+
55
+
56
+ ## License
57
+
58
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
59
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "timed"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/timed/item.rb ADDED
@@ -0,0 +1,96 @@
1
+ module Timed
2
+ # Item
3
+ #
4
+ # The Timed Item is a Moment that can be chained to others to form a sequence.
5
+ # Importantly, items in a sequence are guaranteed to be sequential and non
6
+ # overlapping.
7
+
8
+ class Item < Linked::Item
9
+ include Moment
10
+ # The value field is used to store the timespan and shuold not be accessed
11
+ # directly.
12
+
13
+ protected :value
14
+ private :value=
15
+
16
+ # Creates a new Timed Item from a timespan. A timespan is any object that
17
+ # responds to #begin and #end with two numerical values. Note that the end
18
+ # must occur after the start for the span to be valid.
19
+ #
20
+ # If given a second argument, the two will instead be interpreted as the
21
+ # begin and end time.
22
+ #
23
+ # timespan - object responding to #begin and #end.
24
+ # end_at - if given, it togheter with the first argument will be used as the
25
+ # begin and end time for the item
26
+
27
+ def initialize(timespan, end_at = nil)
28
+ if end_at
29
+ begin_at = timespan
30
+ else
31
+ begin_at = timespan.begin
32
+ end_at = timespan.end
33
+ end
34
+
35
+ raise TypeError unless begin_at.is_a?(Numeric) && end_at.is_a?(Numeric)
36
+ raise ArgumentError if end_at < begin_at
37
+
38
+ super begin_at..end_at
39
+ end
40
+
41
+ # Returns the time when the item starts.
42
+
43
+ def begin
44
+ value.begin
45
+ end
46
+
47
+ # Returns the time when the item ends.
48
+
49
+ def end
50
+ value.end
51
+ end
52
+
53
+ # Returns a new Item in the intersection
54
+ #
55
+ # other - object that implements both #begin and #end.
56
+
57
+ def intersect(other)
58
+ begin_at = self.begin >= other.begin ? self.begin : other.begin
59
+ end_at = self.end <= other.end ? self.end : other.end
60
+
61
+ begin_at <= end_at ? self.class.new(begin_at, end_at) : nil
62
+ end
63
+
64
+ alias & intersect
65
+
66
+ # Inserts an item after this one and before the next in the sequence. The
67
+ # new item may not overlap with the two it sits between. A RuntimeError will
68
+ # be raised if it does.
69
+ #
70
+ # If the given object is an Item it will be inserted directly. Otherwise, if
71
+ # the object responds to #begin and #end, a new Item will be created from
72
+ # that timespan.
73
+
74
+ def append(other)
75
+ raise RuntimeError unless before? other
76
+ raise RuntimeError unless last? || after?(self.next)
77
+
78
+ super
79
+ end
80
+
81
+ # Inserts an item before this one and after the previous in the sequence.
82
+ # The new item may not overlap with the two it sits between. A RuntimeError
83
+ # will be raised if it does.
84
+ #
85
+ # If the given object is an Item it will be inserted directly. Otherwise, if
86
+ # the object responds to #begin and #end, a new Item will be created from
87
+ # that timespan.
88
+
89
+ def prepend(other)
90
+ raise RuntimeError unless after? other
91
+ raise RuntimeError unless first? || before?(previous)
92
+
93
+ super
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Timed
4
+ # Timed Moment
5
+ #
6
+ # By including this module into any object that responds to #begin and #end,
7
+ # it can be compared with other moments in time.
8
+ #
9
+ # To fully support the Moment module the following must hold:
10
+ # a) #begin returns a Numeric value
11
+ # b) #end returns a Numeric value larger than (or equal to) begin
12
+ # c) a new object can be created by a single range-like argument
13
+
14
+ module Moment
15
+ # Returns the moment duration.
16
+
17
+ def duration
18
+ self.end - self.begin
19
+ end
20
+
21
+ # Returns true if the two moments begin and end on exactly the same time.
22
+ #
23
+ # other - object that implements both #begin and #end.
24
+
25
+ def ==(other)
26
+ self.begin == other.begin && self.end == other.end
27
+ rescue NoMethodError
28
+ false
29
+ end
30
+
31
+ # Returns true if the moment ends before the other one begins. If given a
32
+ # numeric value it will be treated like instantaneous moment in time.
33
+ #
34
+ # other - object that implements #begin, or a numeric value.
35
+
36
+ def before?(other)
37
+ time = other.is_a?(Numeric) ? other : other.begin
38
+ self.end <= time
39
+ end
40
+
41
+ # Returns true if the moment begins after the other one ends. If given a
42
+ # numeric value it will be treated like instantaneous moment in time.
43
+ #
44
+ # other - object that implements #end, or a numeric value.
45
+
46
+ def after?(other)
47
+ time = other.is_a?(Numeric) ? other : other.end
48
+ self.begin >= time
49
+ end
50
+
51
+ # Returns true if the moment overlaps with the other one. If given a
52
+ # numeric value it will be treated like instantaneous moment in time.
53
+ #
54
+ # other - object that implements both #begin and #end, or a numeric value.
55
+
56
+ def during?(other)
57
+ if other.is_a? Numeric
58
+ other_begin = other_end = other
59
+ else
60
+ other_begin, other_end = other.begin, other.end
61
+ end
62
+
63
+ self_begin, self_end = self.begin, self.end
64
+
65
+ # Check if either of the two items begins during the
66
+ # span of the other
67
+ other_begin <= self_begin && self_begin <= other_end ||
68
+ self_begin <= other_begin && other_begin <= self_end
69
+ end
70
+
71
+ # Returns a new moment in the intersection
72
+ #
73
+ # other - object that implements both #begin and #end.
74
+
75
+ def intersect(other)
76
+ begin_at = self.begin >= other.begin ? self.begin : other.begin
77
+ end_at = self.end <= other.end ? self.end : other.end
78
+
79
+ begin_at <= end_at ? self.class.new(begin_at..end_at) : nil
80
+ end
81
+
82
+ alias & intersect
83
+
84
+ # Compare the moments with others.
85
+ #
86
+ # Return -1 if the item is before the other, 0 if they overlap and 1 if the
87
+ # item is after the other.
88
+
89
+ # def <=>(other)
90
+ # case
91
+ # when before?(other) then -1
92
+ # when after?(other) then 1
93
+ # else 0
94
+ # end
95
+ # end
96
+
97
+ # Override the default implementation and provide a more useful
98
+ # representation of the Timed Moment, including when it begins and ends.
99
+ #
100
+ # Example
101
+ # moment.inspect # => "ClassName 12.20 -> 15.50"
102
+ #
103
+ # Returns a string representation of the object.
104
+
105
+ def inspect
106
+ format '%s %7.2f -> %.2f', self.class.name, self.begin, self.end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,154 @@
1
+ module Timed
2
+ # Sequence
3
+ #
4
+ # This class implements a sequence of Timed Items. Any object that implements
5
+ # the methods #begin and #end can be push to the sequence. Note that the items
6
+ # must be inserted in chronological order, or the sequence will raise an
7
+ # exception.
8
+ #
9
+ # Example
10
+ # sequence = Timed::Sequence.new
11
+ # sequence << 2..3
12
+ # sequence.prepend Timed::Item.new 1..2 # Same result as above
13
+ #
14
+ # A sequence can also be treated like a Moment and be compared, in time, with
15
+ # other compatible objects.
16
+
17
+ class Sequence
18
+ include Moment
19
+ include Linked::List
20
+
21
+ # Returns the time at which the first item in the sequence, and therefore
22
+ # the sequence as a whole, begins. If the sequence is empty, by convention,
23
+ # it both begins and ends at time 0, giving it a 0 length.
24
+
25
+ def begin
26
+ empty? ? 0 : first.begin
27
+ end
28
+
29
+ # Returns the time at which the last item in the sequence, and therefore
30
+ # the sequence as a whole, ends. If the sequence is empty, by convention,
31
+ # it both begins and ends at time 0, giving it a 0 length.
32
+
33
+ def end
34
+ empty? ? 0 : last.end
35
+ end
36
+
37
+ # Returns the total time made up by the items
38
+
39
+ def time
40
+ each_item.reduce(0) { |a, e| a + e.duration }
41
+ end
42
+
43
+ # Extends the standard behaviour of Linked::List#first with the option of
44
+ # only returning items that begin after a specified time.
45
+ #
46
+ # after - a time after which the returned item(s) must occur.
47
+ #
48
+ # Returns one or more items, or nil if there are no items after the given
49
+ # time.
50
+
51
+ def first(n = 1, after: nil, &block)
52
+ return super(n, &block) unless after
53
+
54
+ if include? after
55
+ first_item_after after, n
56
+ else
57
+ super(n) { |item| item.after? after }
58
+ end
59
+ end
60
+
61
+ # Extends the standard behaviour of Linked::List#last with the option of
62
+ # only returning items that end before a specified time.
63
+ #
64
+ # after - a time after which the returned item(s) must occur.
65
+ #
66
+ # Returns one or more items, or nil if there are no items before the given
67
+ # time.
68
+
69
+ def last(n = 1, before: nil, &block)
70
+ return super(n, &block) unless before
71
+
72
+ if include? before
73
+ last_item_before before, n
74
+ else
75
+ super(n) { |item| item.before? before }
76
+ end
77
+ end
78
+
79
+ # This method takes a second sequence and iterates over each intersection
80
+ # between the two. If a block is given, the beginning and end of each
81
+ # intersecting period will be yielded to it. Otherwise an enumerator is
82
+ # returned.
83
+ #
84
+ # other - a sequence, or object that responds to #begin and #end and returns
85
+ # a Timed::Item in response to #first
86
+ #
87
+ # Returns an enumerator unless a block is given, in which case the number of
88
+ # intersections is returned.
89
+
90
+ def intersections(other)
91
+ return to_enum __callee__, other unless block_given?
92
+
93
+ return unless during? other
94
+
95
+ # Sort the first items from each sequence into leading
96
+ # and trailing by whichever begins first
97
+ if self.begin <= other.begin
98
+ item_l, item_t = first, other.first
99
+ else
100
+ item_l, item_t = other.first, first
101
+ end
102
+
103
+ count = 0
104
+
105
+ loop do
106
+ # Now there are three posibilities:
107
+
108
+ # 1: The leading item ends before the trailing one
109
+ # begins. In this case the items do not intersect
110
+ # at all and we do nothing.
111
+ if item_l.end <= item_t.begin
112
+
113
+ # 2: The leading item ends before the trailing one
114
+ # ends
115
+ elsif item_l.end <= item_t.end
116
+ yield item_t.begin, item_l.end
117
+ count += 1
118
+
119
+ # 3: The leading item ends after the trailing one
120
+ else
121
+ yield item_t.begin, item_t.end
122
+ count += 1
123
+
124
+ # Swap leading and trailing
125
+ item_l, item_t = item_t, item_l
126
+ end
127
+
128
+ # Advance the leading item
129
+ item_l = item_l.next
130
+
131
+ # Swap leading and trailing if needed
132
+ item_l, item_t = item_t, item_l if item_l.begin > item_t.begin
133
+ end
134
+
135
+ count
136
+ end
137
+
138
+ # Returns a new sequence with items that make up the intersection between
139
+ # the two sequences.
140
+
141
+ def intersect(other)
142
+ intersections(other)
143
+ .with_object(self.class.new) { |(b, e), a| a << Item.new(b, e) }
144
+ end
145
+
146
+ alias & intersect
147
+
148
+ # More efficient than first calling #intersect and then #time on the result.
149
+
150
+ def intersect_time(other)
151
+ intersections(other).reduce(0) { |a, (b, e)| a + e - b }
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Timed
4
+ VERSION = '0.1.0'
5
+ end
data/lib/timed.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'linked'
2
+ require 'timed/version'
3
+ require 'timed/moment'
4
+ require 'timed/item'
5
+ require 'timed/sequence'
6
+
7
+ module Timed
8
+
9
+ end
data/timed.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'timed/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "timed"
8
+ spec.version = Timed::VERSION
9
+ spec.authors = ["Sebastian Lindberg"]
10
+ spec.email = ["seb.lindberg@gmail.com"]
11
+
12
+ spec.summary = %q{Gem for working with timed, ordered items.}
13
+ #spec.description = %q{TODO: Write a longer description or delete this line.}
14
+ spec.homepage = "https://github.com/seblindberg/ruby-timed"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "linked", "~> 0.1.3"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.12"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest", "~> 5.0"
27
+ spec.add_development_dependency "coveralls", "~> 0.8"
28
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timed
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Lindberg
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: linked
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.12'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coveralls
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.8'
83
+ description:
84
+ email:
85
+ - seb.lindberg@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - lib/timed.rb
99
+ - lib/timed/item.rb
100
+ - lib/timed/moment.rb
101
+ - lib/timed/sequence.rb
102
+ - lib/timed/version.rb
103
+ - timed.gemspec
104
+ homepage: https://github.com/seblindberg/ruby-timed
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.5.1
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Gem for working with timed, ordered items.
128
+ test_files: []