ocarina_of_time 1.0.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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +167 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/debug.rb +5 -0
- data/lib/ocarina_of_time.rb +56 -0
- data/lib/ocarina_of_time/event.rb +64 -0
- data/lib/ocarina_of_time/events.rb +193 -0
- data/lib/ocarina_of_time/timeline.rb +243 -0
- data/lib/ocarina_of_time/version.rb +3 -0
- data/ocarina_of_time.gemspec +26 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c76b5c32fdda58e5ba617450ad0f9acee53b290a
|
4
|
+
data.tar.gz: caddfbedba3fe902dce0c19604a71388cd2633d5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 297211847d7ab989b49df4ccdaa6fcf8955ea1abef018dcded9b0b0255a9706d8573e399fcadfd1bf332839b3f6e6bdfb725968db9d5c2210a8e86b4c89f7185
|
7
|
+
data.tar.gz: 581dd32dc21fa8bad047554d9dcdeed68207a0f6f2c072c108797014ba7cc62256e44545b3b724c4b7ffdc2ec9d2147e286461acf5ab48c7f0fec099668af44b
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at kgruber1@emich.edu. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Kent Gruber
|
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,167 @@
|
|
1
|
+
# Ocarina of Time
|
2
|
+

|
3
|
+
|
4
|
+
Play this song near a blue Time Block.
|
5
|
+
|
6
|
+
```
|
7
|
+
------------------------------------------------
|
8
|
+
-( > )---------( > )----------------------------
|
9
|
+
----------( v )-----------( > )-----------------
|
10
|
+
-----( A )-----------( A )----------------------
|
11
|
+
```
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
$ gem install ocarina_of_time
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'ocarina_of_time'
|
21
|
+
|
22
|
+
timeline = OcarinaOfTime::Timeline.new
|
23
|
+
|
24
|
+
# beginning of time
|
25
|
+
timeline.beginning
|
26
|
+
# => 2017-02-21 10:10:16 -0500
|
27
|
+
|
28
|
+
# check for beginning of time
|
29
|
+
timeline.beginning?
|
30
|
+
|
31
|
+
# end of time
|
32
|
+
timeline.ending
|
33
|
+
# => false
|
34
|
+
|
35
|
+
# check for end of time
|
36
|
+
timeline.ending?
|
37
|
+
# => false
|
38
|
+
|
39
|
+
# set beginning of end of time
|
40
|
+
timeline.ending = Time.now
|
41
|
+
|
42
|
+
timeline.ending?
|
43
|
+
# => true
|
44
|
+
|
45
|
+
timeline.ending
|
46
|
+
# => 2017-02-21 10:15:45 -0500
|
47
|
+
```
|
48
|
+
|
49
|
+
## Timeline
|
50
|
+
A timeline is a way of displaying a list of events in chronological order, sometimes described as a project artifact. Timelines can use any time scale, depending on the subject and data. Most timelines use a linear scale, where a unit of distance is equal to a set amount of time.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
# will return a unique id number for the timeline event
|
54
|
+
timeline.events.add(label: "Example 1")
|
55
|
+
# => "e41fdc5c-6a8d-4d85-addb-27b6f81666e9"
|
56
|
+
|
57
|
+
# you can remove a timeline event by id number
|
58
|
+
timeline.events.delete(id: "e41fdc5c-6a8d-4d85-addb-27b6f81666e9")
|
59
|
+
# => true
|
60
|
+
|
61
|
+
# or you can remove a timeline event by time, if
|
62
|
+
# it exists -- maybe it's already been deleted ;)
|
63
|
+
timeline.events.delete(id: "e41fdc5c-6a8d-4d85-addb-27b6f81666e9")
|
64
|
+
# => false
|
65
|
+
```
|
66
|
+
|
67
|
+
## Events
|
68
|
+
Timelines events are stored in an events class which acts as a nice wrapped to our timeline Event objects.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
# create new timeline
|
72
|
+
timeline = OcarinaOfTime::Line.new
|
73
|
+
|
74
|
+
# adding events is very straightforward
|
75
|
+
timeline.events.add(label: "Example 1")
|
76
|
+
# => OcarinaOfTime::Event:0x00000001fcd040.id
|
77
|
+
timeline.events.add(label: "Example 2")
|
78
|
+
# => OcarinaOfTime::Event:0x00000001cabce0.id
|
79
|
+
|
80
|
+
# you can easily update events
|
81
|
+
timeline.events.update(id: "2f6716b1-9a2f-46d2-8bcf-4db0212032f1", value: 1)
|
82
|
+
|
83
|
+
# you can easily delete events
|
84
|
+
timelines.events.delete(id: "2f6716b1-9a2f-46d2-8bcf-4db0212032f1")
|
85
|
+
|
86
|
+
# there's a nice little wrapped to sort_by
|
87
|
+
timeline.events.by(oldest: true)
|
88
|
+
# => OcarinaOfTime::Event:0x00000001cabce0, OcarinaOfTime::Event:0x00000001fcd040
|
89
|
+
timeline.events.by(newest: true)
|
90
|
+
# => OcarinaOfTime::Event:0x00000001fcd040, OcarinaOfTime::Event:0x00000001cabce0
|
91
|
+
|
92
|
+
# you can also find events based on different attributes
|
93
|
+
timeline.events.find(label: "Example 1")
|
94
|
+
timeline.events.find(labels: ["Example 1", "Example 2"])
|
95
|
+
timeline.events.find(event: timeline.events.all.first)
|
96
|
+
timeline.events.find(date: Time.now.to_date)
|
97
|
+
|
98
|
+
# you can also chain your find queries ( one option at a time )
|
99
|
+
timeline.events.find(date: Time.now.to_date).find(label: "Example 1")
|
100
|
+
|
101
|
+
# you can get a shortcut to all of the uniqe dates for each event
|
102
|
+
timeline.events.dates
|
103
|
+
# or a shortcut to all of the unique times for each event
|
104
|
+
timeline.events.times
|
105
|
+
# or you can get all of the unique labels
|
106
|
+
timelines.events.labels
|
107
|
+
# or you can get all of the unique ids
|
108
|
+
timelines.events.ids
|
109
|
+
# or you can get all of the unique tags
|
110
|
+
timelines.events.tags
|
111
|
+
|
112
|
+
# or if you don't want unique whatever, turn that off
|
113
|
+
timelines.events.tags(unique: false)
|
114
|
+
timelines.events.times(unique: false)
|
115
|
+
```
|
116
|
+
|
117
|
+
## Event
|
118
|
+
Timeline Events are made up of serveral Event objects. An event object is made up of its unique ID number,
|
119
|
+
its label, its tags ( as a set, unique ), the time of the event ( default to its creation time ), the time
|
120
|
+
the event was created ( defaults to its creation time ) and a value -- which can be whatever you like, if you
|
121
|
+
want to use that ( instead of just stuffing that data in tags ).
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
# create a new timeline event
|
125
|
+
event = OcarinaOfTime::Event.new
|
126
|
+
|
127
|
+
# accessing event data ( reading ) with data shortcuts
|
128
|
+
event.label
|
129
|
+
# => false
|
130
|
+
|
131
|
+
# accessing event data ( to change )
|
132
|
+
event.data.label = "Example 1"
|
133
|
+
|
134
|
+
event.label
|
135
|
+
# => "Example 1"
|
136
|
+
|
137
|
+
# check for tags
|
138
|
+
event.tags?
|
139
|
+
# => false
|
140
|
+
|
141
|
+
# add tags as an array or string
|
142
|
+
tags = ["Cool", "Sick", "Awesome"]
|
143
|
+
tag = "Gnarly"
|
144
|
+
event.add_tags(tags)
|
145
|
+
event.add_tags(tag)
|
146
|
+
|
147
|
+
# check for tags again
|
148
|
+
event.tags?
|
149
|
+
# => true
|
150
|
+
|
151
|
+
# check out tags data
|
152
|
+
event.tags
|
153
|
+
# => Set: {"Cool", "Sick", "Awesome", "Gnarly"}
|
154
|
+
|
155
|
+
# add the same event to two different timelines
|
156
|
+
timeline1 = OcarinaOfTime::Line.new
|
157
|
+
timeline2 = OcarinaOfTime::Line.new
|
158
|
+
timeline1.events.add(event: event)
|
159
|
+
# => "bb2aa0a0-68ee-469c-808b-875c7494a3c4"
|
160
|
+
timeline2.events.add(event: event)
|
161
|
+
# => "bb2aa0a0-68ee-469c-808b-875c7494a3c4"
|
162
|
+
```
|
163
|
+
|
164
|
+
## License
|
165
|
+
|
166
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
167
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ocarina_of_time"
|
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(__FILE__)
|
data/bin/setup
ADDED
data/examples/debug.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# This file is part of Ocarina of Time
|
3
|
+
# See https://github.com/picatz/ocarina_of_time for more information
|
4
|
+
# Copyright (C) 2017 Kent 'picat' Gruber
|
5
|
+
# This program is published under MIT license.
|
6
|
+
|
7
|
+
# TODO: Fix inline documentation.
|
8
|
+
|
9
|
+
require "ocarina_of_time/version"
|
10
|
+
require "ocarina_of_time/timeline"
|
11
|
+
require "ocarina_of_time/event"
|
12
|
+
require "ocarina_of_time/events"
|
13
|
+
|
14
|
+
require 'set'
|
15
|
+
require 'date'
|
16
|
+
require 'time'
|
17
|
+
require 'ostruct'
|
18
|
+
require 'securerandom'
|
19
|
+
|
20
|
+
# The Ocarina of Time is a ruby gem to manage timelines.
|
21
|
+
# @author Kent 'picat' Gruber
|
22
|
+
module OcarinaOfTime
|
23
|
+
# Easter Egg:
|
24
|
+
# /@
|
25
|
+
# __ __ /\/
|
26
|
+
# /==\ / \_/\/
|
27
|
+
# /======\ \/\__ \__
|
28
|
+
# /==/\ /\==\ /\_|__ \
|
29
|
+
# /==/ || \=\ / / / /_/
|
30
|
+
# /=/ /\ || /\ \=\/ /
|
31
|
+
# /===/ / \||/ \ \===\
|
32
|
+
# /===/ /_________________ \===\
|
33
|
+
# /====/ / | / \====\
|
34
|
+
# /====/ / | _________ / \ \===\ THE LEGEND OF
|
35
|
+
# /==/ / | / / \ / / / __________\_____ ______ ___
|
36
|
+
#|===| / |/ /____/ / / \ _____ |\ / \ _ \ \ \
|
37
|
+
# \==\ /\ / / / | | /= \| | | | | \ \ / _ \
|
38
|
+
# \===\__ \ / \ / / / / | | /===/ | | | | \ \ / / \ \
|
39
|
+
# \==\ \ \\ /____/ /_\ // | |_____/| | | | | | | / /___\ \
|
40
|
+
# \===\ \ \\\\\\\/ /////// /| _____ | | | | | | | | ___ |
|
41
|
+
# \==\/ \\\\/ / ////// \| |/==/ \| | | | | | | | / \ |
|
42
|
+
# \==\ _ \\/ / ///// _ | |==/ | | | | / / | | | |
|
43
|
+
# \==\ / \ / / /// /|\| |_____/| | |_____/| | |_/ / | | | |
|
44
|
+
# \==\ / / / /________/ |/_________|/_________|/_____/ /___\ /___\ ゼルダの伝説
|
45
|
+
# \==\ / | /==/
|
46
|
+
# \=\ /________________|/=/ OCARINA OF TIME
|
47
|
+
# \==\ _____ /==/
|
48
|
+
# / \===\ \ / /===/
|
49
|
+
# / / /\===\ \_/ /===/
|
50
|
+
# / / / \====\ /====/
|
51
|
+
# / / / \===|===/
|
52
|
+
# |/_/ \===/
|
53
|
+
# =
|
54
|
+
# credit : http://www.ascii-code.com/ascii-art/video-games/zelda.php
|
55
|
+
#
|
56
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module OcarinaOfTime
|
2
|
+
|
3
|
+
Struct.new("EventData", :id, :label, :tags, :time, :created, :value)
|
4
|
+
|
5
|
+
class Event
|
6
|
+
|
7
|
+
attr_reader :data
|
8
|
+
|
9
|
+
def initialize(args={})
|
10
|
+
@data = Struct::EventData.new
|
11
|
+
@data.id = SecureRandom.uuid
|
12
|
+
@data.label = args[:label] || false
|
13
|
+
@data.value = args[:value] || false
|
14
|
+
@data.tags = Set.new
|
15
|
+
creation_time = Time.now
|
16
|
+
@data.time = args[:time] || creation_time
|
17
|
+
@data.created = args[:created] || creation_time
|
18
|
+
if args[:tags]
|
19
|
+
add_tags(args[:tags])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def id
|
24
|
+
@data.id
|
25
|
+
end
|
26
|
+
|
27
|
+
def label
|
28
|
+
@data.label
|
29
|
+
end
|
30
|
+
|
31
|
+
def time
|
32
|
+
@data.time
|
33
|
+
end
|
34
|
+
|
35
|
+
def created
|
36
|
+
@data.created
|
37
|
+
end
|
38
|
+
|
39
|
+
def time?
|
40
|
+
@data.tags.time ? true : false
|
41
|
+
end
|
42
|
+
|
43
|
+
def tags
|
44
|
+
@data.tags.to_a
|
45
|
+
end
|
46
|
+
|
47
|
+
def tags?
|
48
|
+
@data.tags.empty? ? false : true
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_tags(tags)
|
52
|
+
if tags.is_a? Array
|
53
|
+
tags.each do |tag|
|
54
|
+
@data.tags << tag
|
55
|
+
end
|
56
|
+
elsif tags.is_a? String
|
57
|
+
@data.tags << tags
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module OcarinaOfTime
|
2
|
+
|
3
|
+
class Events
|
4
|
+
|
5
|
+
attr_reader :all
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@all = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def by(args={})
|
12
|
+
results = []
|
13
|
+
if args[:newest]
|
14
|
+
@all.each.sort_by { |e| e.time }.each do |event|
|
15
|
+
results << event
|
16
|
+
end
|
17
|
+
elsif args[:oldest]
|
18
|
+
@all.each.sort_by { |e| e.time }.reverse.each do |event|
|
19
|
+
results << event
|
20
|
+
end
|
21
|
+
else
|
22
|
+
@all
|
23
|
+
end
|
24
|
+
results.empty? ? false : results
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(args={})
|
28
|
+
if args[:event]
|
29
|
+
@all << args[:event]
|
30
|
+
return args[:event].id
|
31
|
+
end
|
32
|
+
event = Event.new
|
33
|
+
event.data.label = args[:label] || false
|
34
|
+
event.add_tags(args[:tags]) if args[:tags]
|
35
|
+
event.data.time = args[:time] if args[:time]
|
36
|
+
@all << event
|
37
|
+
event.id
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(args={})
|
41
|
+
if args[:id]
|
42
|
+
@all.delete_if { |e| e.id == args[:id] }
|
43
|
+
elsif args[:event]
|
44
|
+
@all.delete_if { |e| e == args[:event] }
|
45
|
+
else
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def update(args={})
|
52
|
+
if args[:id]
|
53
|
+
@all.each do |event|
|
54
|
+
if event.id == args[:id]
|
55
|
+
event.add_tags(args[:tags]) if args[:tags]
|
56
|
+
event.data.label = args[:label] if args[:label]
|
57
|
+
event.data.created = args[:created] if args[:created]
|
58
|
+
event.data.value = args[:value] if args[:value]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
elsif args[:label]
|
62
|
+
@all.each do |event|
|
63
|
+
if event.label == args[:label]
|
64
|
+
event.add_tags(args[:tags]) if args[:tags]
|
65
|
+
event.data.label = args[:label] if args[:label]
|
66
|
+
event.data.created = args[:created] if args[:created]
|
67
|
+
event.data.value = args[:value] if args[:value]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
elsif args[:tag]
|
71
|
+
@all.each do |event|
|
72
|
+
if event.tags.include?(args[:tag])
|
73
|
+
event.add_tags(args[:tags]) if args[:tags]
|
74
|
+
event.data.label = args[:label] if args[:label]
|
75
|
+
event.data.created = args[:created] if args[:created]
|
76
|
+
event.data.value = args[:value] if args[:value]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
elsif args[:date]
|
80
|
+
@all.each do |event|
|
81
|
+
if event.time.to_date == args[:date]
|
82
|
+
event.add_tags(args[:tags]) if args[:tags]
|
83
|
+
event.data.label = args[:label] if args[:label]
|
84
|
+
event.data.created = args[:created] if args[:created]
|
85
|
+
event.data.value = args[:value] if args[:value]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
elsif args[:time]
|
89
|
+
@all.each do |event|
|
90
|
+
if event.time == args[:time]
|
91
|
+
event.add_tags(args[:tags]) if args[:tags]
|
92
|
+
event.data.label = args[:label] if args[:label]
|
93
|
+
event.data.created = args[:created] if args[:created]
|
94
|
+
event.data.value = args[:value] if args[:value]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def find(args={})
|
101
|
+
results = Events.new
|
102
|
+
if args[:id]
|
103
|
+
@all.each { |e| results.all << e if e.id == args[:id] }
|
104
|
+
elsif args[:time]
|
105
|
+
@all.each { |e| results.all << e if e.time == args[:time] }
|
106
|
+
elsif args[:date]
|
107
|
+
@all.each { |e| results.all << e if e.time.to_date == args[:date] }
|
108
|
+
elsif args[:event]
|
109
|
+
@all.each { |e| results.all << e if e == args[:event] }
|
110
|
+
elsif args[:label]
|
111
|
+
@all.each { |e| results.all << e if e.label == args[:label] }
|
112
|
+
elsif args[:labels]
|
113
|
+
args[:labels].each do |label|
|
114
|
+
@all.each { |e| results.all << e if e.label == label }
|
115
|
+
end
|
116
|
+
elsif args[:tags]
|
117
|
+
args[:tags].each do |tag|
|
118
|
+
@all.each { |e| results.all << e if e.tags.include?(tag) }
|
119
|
+
end
|
120
|
+
elsif args[:tag]
|
121
|
+
@all.each { |e| results.all << e if e.tag == args[:tag] }
|
122
|
+
else
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
results
|
126
|
+
end
|
127
|
+
|
128
|
+
def ids(args={unique: true})
|
129
|
+
if args[:unique]
|
130
|
+
ids = Set.new
|
131
|
+
else
|
132
|
+
ids = []
|
133
|
+
end
|
134
|
+
@all.each { |e| ids << e.id }
|
135
|
+
ids.to_a
|
136
|
+
end
|
137
|
+
|
138
|
+
def times(args={unique: true})
|
139
|
+
if args[:unique]
|
140
|
+
times = Set.new
|
141
|
+
else
|
142
|
+
times = []
|
143
|
+
end
|
144
|
+
@all.each { |e| times << e.time }
|
145
|
+
times.to_a
|
146
|
+
end
|
147
|
+
|
148
|
+
def dates(args={unique: true})
|
149
|
+
if args[:unique]
|
150
|
+
dates = Set.new
|
151
|
+
else
|
152
|
+
dates = []
|
153
|
+
end
|
154
|
+
@all.each { |e| dates << e.time.to_date }
|
155
|
+
dates.to_a
|
156
|
+
end
|
157
|
+
|
158
|
+
def tags(args={unique: true})
|
159
|
+
if args[:unique]
|
160
|
+
tags = Set.new
|
161
|
+
else
|
162
|
+
tags = []
|
163
|
+
end
|
164
|
+
@all.each do |e|
|
165
|
+
e.tags.to_a.each { |t| tags << t }
|
166
|
+
end
|
167
|
+
tags.to_a
|
168
|
+
end
|
169
|
+
|
170
|
+
def labels(args={unique: true})
|
171
|
+
if args[:unique]
|
172
|
+
labels = Set.new
|
173
|
+
else
|
174
|
+
labels = []
|
175
|
+
end
|
176
|
+
@all.each { |e| labels << e.label }
|
177
|
+
labels.to_a
|
178
|
+
end
|
179
|
+
|
180
|
+
def values(args={unique: true})
|
181
|
+
if args[:unique]
|
182
|
+
values = Set.new
|
183
|
+
else
|
184
|
+
values = []
|
185
|
+
end
|
186
|
+
@all.each { |e| values << e.value }
|
187
|
+
labels.to_a
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
module OcarinaOfTime
|
2
|
+
|
3
|
+
# Respresent the logic of a Timeline.
|
4
|
+
# @author Kent 'picat' Gruber
|
5
|
+
class Timeline
|
6
|
+
|
7
|
+
attr_accessor :beginning
|
8
|
+
attr_accessor :ending
|
9
|
+
attr_accessor :events
|
10
|
+
|
11
|
+
# Create a new **Timeline** object.
|
12
|
+
#
|
13
|
+
# @param [Hash] args arguments for method
|
14
|
+
# @option args [Time] :begin beginning point in time (default: +Time.now+)
|
15
|
+
# @option args [Time] :end ending point in time (default: false)
|
16
|
+
# @return [void]
|
17
|
+
def initialize(args={})
|
18
|
+
@beginning = args[:begin] || Time.now
|
19
|
+
@ending = args[:end] || false
|
20
|
+
@flex = false # have a rigid timeline
|
21
|
+
@events = Events.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# Turn on a flexible timeline, where events will change the potential
|
25
|
+
# range of the timeline. If a beginning is set, an unflexible timeline
|
26
|
+
# will not allow any new events to be set before that time. A flexible timeline
|
27
|
+
# would set the newest ending if the event is before the current one. The same logic
|
28
|
+
# applies to an ending time which may or may not be set. Meaning, an unflexible timeline
|
29
|
+
# makes it very easy to grow ( by moving forward in time ) if there is no ending set.
|
30
|
+
def flex(on = true)
|
31
|
+
on ? @flex = true : @flex = false
|
32
|
+
end
|
33
|
+
|
34
|
+
# Check if the Timeline is flexible or not.
|
35
|
+
#
|
36
|
+
# @return[Boolean]
|
37
|
+
def flex?
|
38
|
+
@flex ? true : false
|
39
|
+
end
|
40
|
+
|
41
|
+
# Check if there's currently a end of time
|
42
|
+
# associated with the timeline object.
|
43
|
+
#
|
44
|
+
# @return[Boolean]
|
45
|
+
def ending?
|
46
|
+
@ending ? true : false
|
47
|
+
end
|
48
|
+
|
49
|
+
# Check if there's currently a beginning of time
|
50
|
+
# associated with the timeline object.
|
51
|
+
#
|
52
|
+
# @return[Boolean]
|
53
|
+
def beginning?
|
54
|
+
@beginning ? true : false
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get the difference in time between +two+ points in +time+.
|
58
|
+
#
|
59
|
+
# @param [Hash] args arguments for method
|
60
|
+
# @option args [Time] :begin beginning point in time
|
61
|
+
# @option args [Time] :end ending point in time
|
62
|
+
# @option args [Time] :seconds get difference in seconds ( default )
|
63
|
+
# @option args [Time] :minutes get difference in minutes
|
64
|
+
# @option args [Time] :hours get difference in hours
|
65
|
+
# @option args [Time] :days get difference in days
|
66
|
+
# @option args [Time] :weeks get difference in weeks
|
67
|
+
# @option args [Time] :years get difference in years
|
68
|
+
# @option args [Time] :decades get difference in decades
|
69
|
+
# @option args [Time] :centuries get difference in centuries
|
70
|
+
# @return [Float] the difference between two points
|
71
|
+
#
|
72
|
+
# == Example
|
73
|
+
# # generate new timeline
|
74
|
+
# timeline = OcarinaOfTime::Line.new
|
75
|
+
# # get days between two times
|
76
|
+
# timeline.time_between(end: Time.now+87654, days: true)
|
77
|
+
# # => 1.0150320438273612
|
78
|
+
# timeline.time_between(end: Time.now+8070654, days: true)
|
79
|
+
# # => 93.41134454091606
|
80
|
+
# timeline.time_between(end: Time.now+8070654, weeks: true)
|
81
|
+
# # => 13.344522046096547
|
82
|
+
#
|
83
|
+
# == Example
|
84
|
+
# # generate new time line
|
85
|
+
# time_line = OcarinaOfTime::Line.new
|
86
|
+
# # set end of time ( default is Time.now for beginning )
|
87
|
+
# time_line.end_of_time = Time.now+8070654
|
88
|
+
# # get time between the two points in minutes
|
89
|
+
# time_line.time_between(minutes: true)
|
90
|
+
# # => 134511.16985055877
|
91
|
+
#
|
92
|
+
def time_between(args={})
|
93
|
+
if args[:begin].is_a? Event
|
94
|
+
start = args[:begin].time
|
95
|
+
else
|
96
|
+
start = args[:begin] || @beginning
|
97
|
+
end
|
98
|
+
raise "unable to determine first (begin) point" unless start
|
99
|
+
if args[:end]
|
100
|
+
if args[:end].is_a? Event
|
101
|
+
stop = args[:end].time
|
102
|
+
else
|
103
|
+
stop = args[:end]
|
104
|
+
end
|
105
|
+
else
|
106
|
+
stop = @ending if @ending
|
107
|
+
raise "unable to determine second (end) point" unless stop
|
108
|
+
end
|
109
|
+
diff = stop - start
|
110
|
+
if args[:seconds]
|
111
|
+
return diff
|
112
|
+
elsif args[:minutes]
|
113
|
+
return diff / 60
|
114
|
+
elsif args[:hours]
|
115
|
+
return diff / 3600
|
116
|
+
elsif args[:days]
|
117
|
+
return diff / 86400
|
118
|
+
elsif args[:weeks]
|
119
|
+
return diff / 604800
|
120
|
+
elsif args[:years]
|
121
|
+
return diff / 31449600
|
122
|
+
elsif args[:decades]
|
123
|
+
return diff / 314496000
|
124
|
+
elsif args[:centuries]
|
125
|
+
return diff / 3144960000
|
126
|
+
else
|
127
|
+
return diff
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Get the days between +two+ points in +time+.
|
132
|
+
#
|
133
|
+
# @param [Hash] args arguments for method
|
134
|
+
# @option args [Time] :begin beginning point in time
|
135
|
+
# @option args [Time] :end ending point in time
|
136
|
+
# @return [Array<Date>] dates between two points in time
|
137
|
+
#
|
138
|
+
# == Example
|
139
|
+
# # generate new time line
|
140
|
+
# time_line = OcarinaOfTime::Line.new
|
141
|
+
# # get days between two times
|
142
|
+
# time_line.days_between(begin: Time.now - 100000, end: Time.now)
|
143
|
+
# # => [#<Date: 2017-02-19 ((2457804j,0s,0n),+0s,2299161j)>, #<Date: 2017-02-20 ((2457805j,0s,0n),+0s,2299161j)>]
|
144
|
+
def days_between(args={})
|
145
|
+
start = args[:begin] || @beginning
|
146
|
+
if args[:end]
|
147
|
+
stop = args[:end]
|
148
|
+
else
|
149
|
+
stop = @ending if @ending
|
150
|
+
end
|
151
|
+
(start.to_date..stop.to_date).to_a
|
152
|
+
end
|
153
|
+
|
154
|
+
# Parse an array of dates to filter out for specifc days
|
155
|
+
# of the week ( Monday .. Sunday ).
|
156
|
+
#
|
157
|
+
# @param [Hash] arguments for method
|
158
|
+
# @option args [Array<Date>] :days array of dates to work with
|
159
|
+
# @option args [Boolean] :mondays get mondays
|
160
|
+
# @option args [Boolean] :tuesdays get tuesdays
|
161
|
+
# @option args [Boolean] :wednesdays get wednesdays
|
162
|
+
# @option args [Boolean] :thursdays get thursdays
|
163
|
+
# @option args [Boolean] :fridays get fridays
|
164
|
+
# @option args [Boolean] :saturdays get saturdays
|
165
|
+
# @option args [Boolean] :sundays get sundays
|
166
|
+
# @option args [Array<Int>] :years get years
|
167
|
+
# @option args [Array<Int>] :months get months, represented as an int
|
168
|
+
# @return [Array<Date>] parsed dates
|
169
|
+
#
|
170
|
+
# == Example
|
171
|
+
# # generate new time line
|
172
|
+
# time_line = OcarinaOfTime::Line.new
|
173
|
+
# # get days between two times
|
174
|
+
# days = time_line.days_between(begin: Time.now - 10000000, end: Time.now)
|
175
|
+
# # parse days for mondays only
|
176
|
+
# time_line.find_days(days: days, mondays: true)
|
177
|
+
# # parse days for sundays only
|
178
|
+
# time_line.find_days(days: days, sundays: true)
|
179
|
+
# # parse days for wednesdays and fridays only
|
180
|
+
# time_line.find_days(days: days, wednesdays: true, fridays: true)
|
181
|
+
def find_days(args={})
|
182
|
+
unless args[:days]
|
183
|
+
if @ending and @beginning
|
184
|
+
all_days = days_between
|
185
|
+
else
|
186
|
+
raise "need to specify days to work with"
|
187
|
+
end
|
188
|
+
else
|
189
|
+
all_days = args[:days]
|
190
|
+
end
|
191
|
+
days = Set.new
|
192
|
+
all_days.each do |day|
|
193
|
+
days << day if day.monday? and args[:mondays]
|
194
|
+
days << day if day.tuesday? and args[:tuesdays]
|
195
|
+
days << day if day.wednesday? and args[:wednesdays]
|
196
|
+
days << day if day.thursday? and args[:thursdays]
|
197
|
+
days << day if day.friday? and args[:fridays]
|
198
|
+
days << day if day.saturday? and args[:saturdays]
|
199
|
+
days << day if day.sunday? and args[:sundays]
|
200
|
+
end
|
201
|
+
days.to_a
|
202
|
+
end
|
203
|
+
|
204
|
+
# Parse an array of dates to filter out for specifc dates
|
205
|
+
# that match a specific yeay ( 1970, 1994, 2017 .. ect ).
|
206
|
+
#
|
207
|
+
# @param [Hash] arguments for method
|
208
|
+
# @option args [Array<Date>] :days array of dates to work with
|
209
|
+
# @option args [Array, Integer] :years get specific years
|
210
|
+
# @return [Array<Date>] parsed years
|
211
|
+
#
|
212
|
+
# == Example
|
213
|
+
# # generate new time line
|
214
|
+
# time_line = OcarinaOfTime::Line.new
|
215
|
+
# time_line.end_of_time = Time.now+8070654
|
216
|
+
# # parse days for the year 2017
|
217
|
+
# time_line.find_years(years: 2017)
|
218
|
+
# # parse days for the year 2016 or 2017
|
219
|
+
# time_line.find_years(years: [2016, 2017])
|
220
|
+
def find_years(args={})
|
221
|
+
unless args[:days]
|
222
|
+
if @ending and @beginning
|
223
|
+
all_days = days_between
|
224
|
+
else
|
225
|
+
raise "need to specify days to work with"
|
226
|
+
end
|
227
|
+
else
|
228
|
+
all_days = args[:days]
|
229
|
+
end
|
230
|
+
days = Set.new
|
231
|
+
all_days.each do |day|
|
232
|
+
if args[:years]
|
233
|
+
if args[:years].is_a? Array
|
234
|
+
days << day if args[:years].include? day.year
|
235
|
+
elsif args[:years].is_a? Integer
|
236
|
+
days << day if args[:years] == day.year
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
days.to_a
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ocarina_of_time/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ocarina_of_time"
|
8
|
+
spec.version = OcarinaOfTime::VERSION
|
9
|
+
spec.authors = ["Kent Gruber"]
|
10
|
+
spec.email = ["kgruber1@emich.edu"]
|
11
|
+
|
12
|
+
spec.summary = %q{The Ocarina of Time is a ruby gem to manage timelines.}
|
13
|
+
spec.description = %q{The Ocarina of Time is a ruby gem to manage timelines through a simple API to contrsuct timelines and manage the events that happen during the liftime of a timeline.}
|
14
|
+
spec.homepage = "https://github.com/picatz/Ocarina-of-Time"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "bin"
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ocarina_of_time
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kent Gruber
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: The Ocarina of Time is a ruby gem to manage timelines through a simple
|
56
|
+
API to contrsuct timelines and manage the events that happen during the liftime
|
57
|
+
of a timeline.
|
58
|
+
email:
|
59
|
+
- kgruber1@emich.edu
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".gitignore"
|
65
|
+
- ".rspec"
|
66
|
+
- ".travis.yml"
|
67
|
+
- CODE_OF_CONDUCT.md
|
68
|
+
- Gemfile
|
69
|
+
- LICENSE.txt
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- bin/console
|
73
|
+
- bin/setup
|
74
|
+
- examples/debug.rb
|
75
|
+
- lib/ocarina_of_time.rb
|
76
|
+
- lib/ocarina_of_time/event.rb
|
77
|
+
- lib/ocarina_of_time/events.rb
|
78
|
+
- lib/ocarina_of_time/timeline.rb
|
79
|
+
- lib/ocarina_of_time/version.rb
|
80
|
+
- ocarina_of_time.gemspec
|
81
|
+
homepage: https://github.com/picatz/Ocarina-of-Time
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.6.8
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: The Ocarina of Time is a ruby gem to manage timelines.
|
105
|
+
test_files: []
|