nano-smart-lib 0.0.1
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/nano-smart-lib.gemspec +12 -0
- data/timecop-0.9.11/LICENSE +22 -0
- data/timecop-0.9.11/README.markdown +162 -0
- data/timecop-0.9.11/Rakefile +34 -0
- data/timecop-0.9.11/lib/timecop/time_extensions.rb +235 -0
- data/timecop-0.9.11/lib/timecop/time_stack_item.rb +169 -0
- data/timecop-0.9.11/lib/timecop/timecop.rb +264 -0
- data/timecop-0.9.11/lib/timecop/version.rb +3 -0
- data/timecop-0.9.11/lib/timecop.rb +2 -0
- metadata +50 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 3ec09cb5c3f58464babe2db65f3da483fd886681ff9833e77e4bf99e19af42b0
|
|
4
|
+
data.tar.gz: 8a1ab3d749cb4de6baa8326682e2518eda99e02844d3b870316366b8f2d040e1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5d225b4f0c52899e1e628dfe9a7b725ee0b9c7f51337e189ab7f25706205f883215cd4d82c53cff27deafb70d12f0ec24a3d9419f9a9bc1324cc549754198d9b
|
|
7
|
+
data.tar.gz: faa662213b9fe69b4853a0d276695a48d7260ed1ec382fdba551e9fea98341aae98f5d7bd74455d450a568278b705500124882cc120ec4bb4910993361c096fa
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = "nano-smart-lib"
|
|
3
|
+
s.version = "0.0.1"
|
|
4
|
+
s.summary = "Research test"
|
|
5
|
+
s.description = "University research based on timecop"
|
|
6
|
+
s.authors = ["Andrey78"]
|
|
7
|
+
s.email = ["cakoc614@gmail.com"]
|
|
8
|
+
s.files = Dir.glob("**/*").reject { |f| f.end_with?('.gem') }
|
|
9
|
+
s.homepage = "https://rubygems.org/profiles/Andrey78"
|
|
10
|
+
s.license = "MIT"
|
|
11
|
+
s.metadata = { "source_code_uri" => "https://github.com/Andrey78/nano-smart-lib" }
|
|
12
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
(The MIT License)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 — Travis Jeffery, John Trupiano
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# timecop
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/timecop)
|
|
4
|
+
[](https://github.com/travisjeffery/timecop/actions?query=workflow%3ACI)
|
|
5
|
+
|
|
6
|
+
## DESCRIPTION
|
|
7
|
+
|
|
8
|
+
A gem providing "time travel" and "time freezing" capabilities, making it dead simple to test time-dependent code. It provides a unified method to mock `Time.now`, `Date.today`, `DateTime.now`, and `Process.clock_gettime` in a single call.
|
|
9
|
+
|
|
10
|
+
## INSTALL
|
|
11
|
+
|
|
12
|
+
`bundle add timecop`
|
|
13
|
+
|
|
14
|
+
## FEATURES
|
|
15
|
+
|
|
16
|
+
- Freeze time to a specific point.
|
|
17
|
+
- Travel back to a specific point in time, but allow time to continue moving forward from there.
|
|
18
|
+
- Scale time by a given scaling factor that will cause time to move at an accelerated pace.
|
|
19
|
+
- No dependencies, can be used with _any_ ruby project
|
|
20
|
+
- Timecop api allows arguments to be passed into `#freeze` and `#travel` as one of the following:
|
|
21
|
+
- Time instance
|
|
22
|
+
- DateTime instance
|
|
23
|
+
- Date instance
|
|
24
|
+
- individual arguments (year, month, day, hour, minute, second)
|
|
25
|
+
- a single integer argument that is interpreted as an offset in seconds from `Time.now`
|
|
26
|
+
- Nested calls to `Timecop#travel` and `Timecop#freeze` are supported -- each block will maintain its interpretation of now.
|
|
27
|
+
- Works with regular Ruby projects, and Ruby on Rails projects
|
|
28
|
+
|
|
29
|
+
## USAGE
|
|
30
|
+
|
|
31
|
+
Run a time-sensitive test
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
joe = User.find(1)
|
|
35
|
+
joe.purchase_home()
|
|
36
|
+
assert !joe.mortgage_due?
|
|
37
|
+
# move ahead a month and assert that the mortgage is due
|
|
38
|
+
Timecop.freeze(Date.today + 30) do
|
|
39
|
+
assert joe.mortgage_due?
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
You can mock the time for a set of tests easily via setup/teardown methods
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
describe "some set of tests to mock" do
|
|
47
|
+
before do
|
|
48
|
+
Timecop.freeze(Time.local(1990))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
after do
|
|
52
|
+
Timecop.return
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should do blah blah blah" do
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Set the time for the test environment of a rails app -- this is particularly
|
|
61
|
+
helpful if your whole application is time-sensitive. It allows you to build
|
|
62
|
+
your test data at a single point in time, and to move in/out of that time as
|
|
63
|
+
appropriate (within your tests)
|
|
64
|
+
|
|
65
|
+
in `config/environments/test.rb`
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
config.after_initialize do
|
|
69
|
+
# Set Time.now to September 1, 2008 10:05:00 AM (at this instant), but allow it to move forward
|
|
70
|
+
t = Time.local(2008, 9, 1, 10, 5, 0)
|
|
71
|
+
Timecop.travel(t)
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### The difference between Timecop.freeze and Timecop.travel
|
|
76
|
+
|
|
77
|
+
`freeze` is used to statically mock the concept of now. As your program executes,
|
|
78
|
+
`Time.now` will not change unless you make subsequent calls into the Timecop API.
|
|
79
|
+
`travel`, on the other hand, computes an offset between what we currently think
|
|
80
|
+
`Time.now` is (recall that we support nested traveling) and the time passed in.
|
|
81
|
+
It uses this offset to simulate the passage of time. To demonstrate, consider
|
|
82
|
+
the following code snippets:
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
new_time = Time.local(2008, 9, 1, 12, 0, 0)
|
|
86
|
+
Timecop.freeze(new_time)
|
|
87
|
+
sleep(10)
|
|
88
|
+
new_time == Time.now # ==> true
|
|
89
|
+
|
|
90
|
+
Timecop.return # "turn off" Timecop
|
|
91
|
+
Timecop.travel(new_time)
|
|
92
|
+
sleep(10)
|
|
93
|
+
new_time == Time.now # ==> false
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Timecop.scale
|
|
97
|
+
|
|
98
|
+
Let's say you want to test a "live" integration wherein entire days could pass by
|
|
99
|
+
in minutes while you're able to simulate "real" activity. For example, one such use case
|
|
100
|
+
is being able to test reports and invoices that run in 30 day cycles in very little time, while also
|
|
101
|
+
being able to simulate activity via subsequent calls to your application.
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
# seconds will now seem like hours
|
|
105
|
+
Timecop.scale(3600)
|
|
106
|
+
Time.now
|
|
107
|
+
# => 2012-09-20 21:23:25 -0500
|
|
108
|
+
# seconds later, hours have passed and it's gone from 9pm at night to 6am in the morning
|
|
109
|
+
Time.now
|
|
110
|
+
# => 2012-09-21 06:22:59 -0500
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
See [#42](https://github.com/travisjeffery/timecop/pull/42) for more information, thanks to Ken Mayer, David Holcomb, and Pivotal Labs.
|
|
114
|
+
|
|
115
|
+
### Timecop.safe_mode
|
|
116
|
+
|
|
117
|
+
Safe mode forces you to use Timecop with the block syntax since it always puts time back the way it was. If you are running in safe mode and use Timecop without the block syntax `Timecop::SafeModeException` will be raised to tell the user they are not being safe.
|
|
118
|
+
|
|
119
|
+
``` ruby
|
|
120
|
+
# turn on safe mode
|
|
121
|
+
Timecop.safe_mode = true
|
|
122
|
+
|
|
123
|
+
# check if you are in safe mode
|
|
124
|
+
Timecop.safe_mode?
|
|
125
|
+
# => true
|
|
126
|
+
|
|
127
|
+
# using method without block
|
|
128
|
+
Timecop.freeze
|
|
129
|
+
# => Timecop::SafeModeException: Safe mode is enabled, only calls passing a block are allowed.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Configuring Mocking Process.clock_gettime
|
|
133
|
+
|
|
134
|
+
By default Timecop does not mock Process.clock_gettime. You must enable it like this:
|
|
135
|
+
|
|
136
|
+
``` ruby
|
|
137
|
+
# turn on
|
|
138
|
+
Timecop.mock_process_clock = true
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Rails v Ruby Date/Time libraries
|
|
142
|
+
|
|
143
|
+
Sometimes [Rails Date/Time methods don't play nicely with Ruby Date/Time methods.](https://rails.lighthouseapp.com/projects/8994/tickets/6410-dateyesterday-datetoday)
|
|
144
|
+
|
|
145
|
+
Be careful mixing Ruby `Date.today` with Rails `Date.tomorrow` / `Date.yesterday` as things might break.
|
|
146
|
+
|
|
147
|
+
## Contribute
|
|
148
|
+
|
|
149
|
+
timecop is maintained by [travisjeffery](http://github.com/travisjeffery), and
|
|
150
|
+
was created by [jtrupiano](https://github.com/jtrupiano).
|
|
151
|
+
|
|
152
|
+
Here's the most direct way to get your work merged into the project.
|
|
153
|
+
|
|
154
|
+
- Fork the project
|
|
155
|
+
- Clone down your fork
|
|
156
|
+
- Create a feature branch
|
|
157
|
+
- Hack away and add tests, not necessarily in that order
|
|
158
|
+
- Make sure everything still passes by running tests
|
|
159
|
+
- If necessary, rebase your commits into logical chunks without errors
|
|
160
|
+
- Push the branch up to your fork
|
|
161
|
+
- Send a pull request for your branch
|
|
162
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'bundler/setup'
|
|
2
|
+
require 'bundler/gem_tasks'
|
|
3
|
+
require 'rake/testtask'
|
|
4
|
+
require 'rdoc/task'
|
|
5
|
+
|
|
6
|
+
Rake::RDocTask.new do |rdoc|
|
|
7
|
+
if File.exist?('VERSION')
|
|
8
|
+
version = File.read('VERSION')
|
|
9
|
+
else
|
|
10
|
+
version = ""
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
14
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
|
15
|
+
rdoc.title = "timecop #{version}"
|
|
16
|
+
rdoc.rdoc_files.include('README*')
|
|
17
|
+
rdoc.rdoc_files.include('History.rdoc')
|
|
18
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
task :test do
|
|
22
|
+
failed = Dir["test/*_test.rb"].map do |test|
|
|
23
|
+
command = "ruby #{test}"
|
|
24
|
+
puts
|
|
25
|
+
puts command
|
|
26
|
+
command unless system(command)
|
|
27
|
+
end.compact
|
|
28
|
+
if failed.any?
|
|
29
|
+
abort "#{failed.count} Tests failed\n#{failed.join("\n")}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc 'Default: run tests'
|
|
34
|
+
task :default => [:test]
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
require 'time'
|
|
2
|
+
require 'date'
|
|
3
|
+
|
|
4
|
+
class Time #:nodoc:
|
|
5
|
+
class << self
|
|
6
|
+
def mock_time
|
|
7
|
+
mocked_time_stack_item = Timecop.top_stack_item
|
|
8
|
+
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.time(self)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
alias_method :now_without_mock_time, :now
|
|
12
|
+
|
|
13
|
+
def now_with_mock_time
|
|
14
|
+
mock_time || now_without_mock_time
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
alias_method :now, :now_with_mock_time
|
|
18
|
+
|
|
19
|
+
alias_method :new_without_mock_time, :new
|
|
20
|
+
|
|
21
|
+
def new_with_mock_time(*args, **kwargs)
|
|
22
|
+
if args.empty? && kwargs.empty?
|
|
23
|
+
now
|
|
24
|
+
elsif kwargs.any?
|
|
25
|
+
new_without_mock_time(*args, **kwargs)
|
|
26
|
+
else
|
|
27
|
+
new_without_mock_time(*args)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
alias_method :new, :new_with_mock_time
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class Date #:nodoc:
|
|
36
|
+
class << self
|
|
37
|
+
def mock_date
|
|
38
|
+
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.date(self)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
alias_method :today_without_mock_date, :today
|
|
42
|
+
|
|
43
|
+
def today_with_mock_date
|
|
44
|
+
mock_date || today_without_mock_date
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
alias_method :today, :today_with_mock_date
|
|
48
|
+
|
|
49
|
+
alias_method :strptime_without_mock_date, :strptime
|
|
50
|
+
|
|
51
|
+
def strptime_with_mock_date(str = '-4712-01-01', fmt = '%F', start = Date::ITALY)
|
|
52
|
+
#If date is not valid the following line raises
|
|
53
|
+
Date.strptime_without_mock_date(str, fmt, start)
|
|
54
|
+
|
|
55
|
+
d = Date._strptime(str, fmt)
|
|
56
|
+
now = Time.now.to_date
|
|
57
|
+
|
|
58
|
+
# If "current" time falls near a year boundary, with a year-ambiguous str, we need to explicitly handle it
|
|
59
|
+
cwday = d[:cwday] && (now + (d[:cwday] - now.wday))
|
|
60
|
+
wday = d[:wday] && (now + (d[:wday] - now.wday))
|
|
61
|
+
|
|
62
|
+
year = d[:year] || d[:cwyear] || (cwday || wday || now).year
|
|
63
|
+
mon = d[:mon] || now.mon
|
|
64
|
+
if d.keys == [:year]
|
|
65
|
+
Date.new(year, 1, 1, start)
|
|
66
|
+
elsif d[:mday]
|
|
67
|
+
Date.new(year, mon, d[:mday], start)
|
|
68
|
+
elsif d[:yday]
|
|
69
|
+
Date.new(year, 1, 1, start).next_day(d[:yday] - 1)
|
|
70
|
+
elsif d[:cwyear] || d[:cweek] || d[:wnum0] || d[:wnum1] || d[:wday] || d[:cwday]
|
|
71
|
+
# When only a day (wday/cwday) is present, derive the week from the resolved date; otherwise fall back to now's week
|
|
72
|
+
week = d[:cweek] || d[:wnum1] || d[:wnum0] || (cwday || wday || now).strftime('%W').to_i
|
|
73
|
+
if d[:wnum0] #Week of year where week starts on sunday
|
|
74
|
+
if d[:cwday] #monday based day of week
|
|
75
|
+
Date.strptime_without_mock_date("#{year} #{week} #{d[:cwday]}", '%Y %U %u', start)
|
|
76
|
+
else
|
|
77
|
+
Date.strptime_without_mock_date("#{year} #{week} #{d[:wday] || 0}", '%Y %U %w', start)
|
|
78
|
+
end
|
|
79
|
+
else #Week of year where week starts on monday
|
|
80
|
+
if d[:wday] #sunday based day of week
|
|
81
|
+
Date.strptime_without_mock_date("#{year} #{week} #{d[:wday]}", '%Y %W %w', start)
|
|
82
|
+
else
|
|
83
|
+
Date.strptime_without_mock_date("#{year} #{week} #{d[:cwday] || 1}", '%Y %W %u', start)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
elsif d[:seconds]
|
|
87
|
+
Time.at(d[:seconds]).to_date
|
|
88
|
+
else
|
|
89
|
+
Date.new(year, mon, 1, start)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
alias_method :strptime, :strptime_with_mock_date
|
|
94
|
+
|
|
95
|
+
def parse_with_mock_date(*args)
|
|
96
|
+
parsed_date = parse_without_mock_date(*args)
|
|
97
|
+
return parsed_date unless mocked_time_stack_item
|
|
98
|
+
date_hash = Date._parse(*args)
|
|
99
|
+
|
|
100
|
+
case
|
|
101
|
+
when date_hash[:year] && date_hash[:mon]
|
|
102
|
+
parsed_date
|
|
103
|
+
when date_hash[:mon] && date_hash[:mday]
|
|
104
|
+
Date.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
|
|
105
|
+
when date_hash[:mday]
|
|
106
|
+
Date.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
|
|
107
|
+
when date_hash[:wday]
|
|
108
|
+
closest_wday(date_hash[:wday])
|
|
109
|
+
else
|
|
110
|
+
parsed_date + mocked_time_stack_item.travel_offset_days
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
alias_method :parse_without_mock_date, :parse
|
|
115
|
+
alias_method :parse, :parse_with_mock_date
|
|
116
|
+
|
|
117
|
+
def mocked_time_stack_item
|
|
118
|
+
Timecop.top_stack_item
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def closest_wday(wday)
|
|
122
|
+
today = Date.today
|
|
123
|
+
result = today - today.wday
|
|
124
|
+
result += 1 until wday == result.wday
|
|
125
|
+
result
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class DateTime #:nodoc:
|
|
131
|
+
class << self
|
|
132
|
+
def mock_time
|
|
133
|
+
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.datetime(self)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def now_with_mock_time
|
|
137
|
+
mock_time || now_without_mock_time
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
alias_method :now_without_mock_time, :now
|
|
141
|
+
|
|
142
|
+
alias_method :now, :now_with_mock_time
|
|
143
|
+
|
|
144
|
+
def parse_with_mock_date(*args)
|
|
145
|
+
parsed_date = parse_without_mock_date(*args)
|
|
146
|
+
return parsed_date unless mocked_time_stack_item
|
|
147
|
+
date_hash = DateTime._parse(*args)
|
|
148
|
+
|
|
149
|
+
case
|
|
150
|
+
when date_hash[:year] && date_hash[:mon]
|
|
151
|
+
parsed_date
|
|
152
|
+
when date_hash[:mon] && date_hash[:mday]
|
|
153
|
+
DateTime.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
|
|
154
|
+
when date_hash[:mday]
|
|
155
|
+
DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
|
|
156
|
+
when date_hash[:wday] && date_hash[:hour] && date_hash[:min]
|
|
157
|
+
closest_date = Date.closest_wday(date_hash[:wday]).to_datetime
|
|
158
|
+
|
|
159
|
+
DateTime.new(
|
|
160
|
+
closest_date.year, closest_date.month, closest_date.day,
|
|
161
|
+
date_hash[:hour], date_hash[:min]
|
|
162
|
+
)
|
|
163
|
+
when date_hash[:wday]
|
|
164
|
+
Date.closest_wday(date_hash[:wday]).to_datetime
|
|
165
|
+
when date_hash[:hour] && date_hash[:min] && date_hash[:sec]
|
|
166
|
+
DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, mocked_time_stack_item.day, date_hash[:hour], date_hash[:min], date_hash[:sec])
|
|
167
|
+
when date_hash[:hour] && date_hash[:min]
|
|
168
|
+
DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, mocked_time_stack_item.day, date_hash[:hour], date_hash[:min], 0)
|
|
169
|
+
else
|
|
170
|
+
parsed_date + mocked_time_stack_item.travel_offset_days
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
alias_method :parse_without_mock_date, :parse
|
|
175
|
+
alias_method :parse, :parse_with_mock_date
|
|
176
|
+
|
|
177
|
+
def mocked_time_stack_item
|
|
178
|
+
Timecop.top_stack_item
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
module Process #:nodoc:
|
|
184
|
+
class << self
|
|
185
|
+
alias_method :clock_gettime_without_mock, :clock_gettime
|
|
186
|
+
|
|
187
|
+
def clock_gettime_mock_time(clock_id, unit = :float_second)
|
|
188
|
+
mock_time = case clock_id
|
|
189
|
+
when Process::CLOCK_MONOTONIC
|
|
190
|
+
mock_time_monotonic
|
|
191
|
+
when Process::CLOCK_REALTIME
|
|
192
|
+
mock_time_realtime
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
return clock_gettime_without_mock(clock_id, unit) unless Timecop.mock_process_clock? && mock_time
|
|
196
|
+
|
|
197
|
+
divisor = case unit
|
|
198
|
+
when :float_second
|
|
199
|
+
1_000_000_000.0
|
|
200
|
+
when :second
|
|
201
|
+
1_000_000_000
|
|
202
|
+
when :float_millisecond
|
|
203
|
+
1_000_000.0
|
|
204
|
+
when :millisecond
|
|
205
|
+
1_000_000
|
|
206
|
+
when :float_microsecond
|
|
207
|
+
1000.0
|
|
208
|
+
when :microsecond
|
|
209
|
+
1000
|
|
210
|
+
when :nanosecond
|
|
211
|
+
1
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
(mock_time / divisor)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
alias_method :clock_gettime, :clock_gettime_mock_time
|
|
218
|
+
|
|
219
|
+
private
|
|
220
|
+
|
|
221
|
+
def mock_time_monotonic
|
|
222
|
+
mocked_time_stack_item = Timecop.top_stack_item
|
|
223
|
+
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.monotonic
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def mock_time_realtime
|
|
227
|
+
mocked_time_stack_item = Timecop.top_stack_item
|
|
228
|
+
|
|
229
|
+
return nil if mocked_time_stack_item.nil?
|
|
230
|
+
|
|
231
|
+
t = mocked_time_stack_item.time
|
|
232
|
+
t.to_i * 1_000_000_000 + t.nsec
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
class Timecop
|
|
2
|
+
# A data class for carrying around "time movement" objects. Makes it easy to keep track of the time
|
|
3
|
+
# movements on a simple stack.
|
|
4
|
+
class TimeStackItem #:nodoc:
|
|
5
|
+
attr_reader :mock_type
|
|
6
|
+
|
|
7
|
+
def initialize(mock_type, *args)
|
|
8
|
+
raise "Unknown mock_type #{mock_type}" unless [:freeze, :travel, :scale].include?(mock_type)
|
|
9
|
+
@travel_offset = @scaling_factor = nil
|
|
10
|
+
@scaling_factor = args.shift if mock_type == :scale
|
|
11
|
+
@mock_type = mock_type
|
|
12
|
+
@monotonic = parse_monotonic_time(*args)
|
|
13
|
+
@time = parse_time(*args)
|
|
14
|
+
@time_was = Time.now_without_mock_time
|
|
15
|
+
@travel_offset = compute_travel_offset
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def year
|
|
19
|
+
time.year
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def month
|
|
23
|
+
time.month
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def day
|
|
27
|
+
time.day
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def hour
|
|
31
|
+
time.hour
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def min
|
|
35
|
+
time.min
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def sec
|
|
39
|
+
time.sec
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def utc_offset
|
|
43
|
+
time.utc_offset
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def travel_offset
|
|
47
|
+
@travel_offset unless mock_type == :freeze
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def travel_offset_days
|
|
51
|
+
(@travel_offset / 60 / 60 / 24).round
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def scaling_factor
|
|
55
|
+
@scaling_factor
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def monotonic
|
|
59
|
+
if travel_offset.nil?
|
|
60
|
+
@monotonic
|
|
61
|
+
elsif scaling_factor.nil?
|
|
62
|
+
current_monotonic + travel_offset * (10 ** 9)
|
|
63
|
+
else
|
|
64
|
+
(@monotonic + (current_monotonic - @monotonic) * scaling_factor).to_i
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def current_monotonic
|
|
69
|
+
Process.clock_gettime_without_mock(Process::CLOCK_MONOTONIC, :nanosecond)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def current_monotonic_with_mock
|
|
73
|
+
Process.clock_gettime_mock_time(Process::CLOCK_MONOTONIC, :nanosecond)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def time(time_klass = Time) #:nodoc:
|
|
77
|
+
if @time.respond_to?(:in_time_zone)
|
|
78
|
+
time = time_klass.at(@time.dup.localtime)
|
|
79
|
+
else
|
|
80
|
+
time = time_klass.at(@time)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
if travel_offset.nil?
|
|
84
|
+
time
|
|
85
|
+
elsif scaling_factor.nil?
|
|
86
|
+
time_klass.at(Time.now_without_mock_time + travel_offset)
|
|
87
|
+
else
|
|
88
|
+
time_klass.at(scaled_time)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def scaled_time
|
|
93
|
+
(@time + (Time.now_without_mock_time - @time_was) * scaling_factor).to_f
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def date(date_klass = Date)
|
|
97
|
+
date_klass.jd(time.__send__(:to_date).jd)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def datetime(datetime_klass = DateTime)
|
|
101
|
+
if Float.method_defined?(:to_r)
|
|
102
|
+
fractions_of_a_second = time.to_f % 1
|
|
103
|
+
datetime_klass.new(year, month, day, hour, min, (fractions_of_a_second + sec), utc_offset_to_rational(utc_offset))
|
|
104
|
+
else
|
|
105
|
+
datetime_klass.new(year, month, day, hour, min, sec, utc_offset_to_rational(utc_offset))
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def rational_to_utc_offset(rational)
|
|
112
|
+
((24.0 / rational.denominator) * rational.numerator) * (60 * 60)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def utc_offset_to_rational(utc_offset)
|
|
116
|
+
Rational(utc_offset, 24 * 60 * 60)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def parse_monotonic_time(*args)
|
|
120
|
+
arg = args.shift
|
|
121
|
+
offset_in_nanoseconds = if args.empty? && (arg.kind_of?(Integer) || arg.kind_of?(Float))
|
|
122
|
+
arg * 1_000_000_000
|
|
123
|
+
else
|
|
124
|
+
0
|
|
125
|
+
end
|
|
126
|
+
current_monotonic_with_mock + offset_in_nanoseconds
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def parse_time(*args)
|
|
130
|
+
arg = args.shift
|
|
131
|
+
if arg.is_a?(Time)
|
|
132
|
+
arg
|
|
133
|
+
elsif Object.const_defined?(:DateTime) && arg.is_a?(DateTime)
|
|
134
|
+
time_klass.at(arg.to_time.to_f).getlocal
|
|
135
|
+
elsif Object.const_defined?(:Date) && arg.is_a?(Date)
|
|
136
|
+
time_klass.local(arg.year, arg.month, arg.day, 0, 0, 0)
|
|
137
|
+
elsif args.empty? && (arg.kind_of?(Integer) || arg.kind_of?(Float))
|
|
138
|
+
time_klass.now + arg
|
|
139
|
+
elsif arg.nil?
|
|
140
|
+
time_klass.now
|
|
141
|
+
else
|
|
142
|
+
if arg.is_a?(String) && Time.respond_to?(:parse)
|
|
143
|
+
time_klass.parse(arg)
|
|
144
|
+
else
|
|
145
|
+
# we'll just assume it's a list of y/m/d/h/m/s
|
|
146
|
+
year = arg || 2000
|
|
147
|
+
month = args.shift || 1
|
|
148
|
+
day = args.shift || 1
|
|
149
|
+
hour = args.shift || 0
|
|
150
|
+
minute = args.shift || 0
|
|
151
|
+
second = args.shift || 0
|
|
152
|
+
time_klass.local(year, month, day, hour, minute, second)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def compute_travel_offset
|
|
158
|
+
time - Time.now_without_mock_time
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def times_are_equal_within_epsilon t1, t2, epsilon_in_seconds
|
|
162
|
+
(t1 - t2).abs < epsilon_in_seconds
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def time_klass
|
|
166
|
+
Time.respond_to?(:zone) && Time.zone ? Time.zone : Time
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
require File.join(File.dirname(__FILE__), "time_stack_item")
|
|
3
|
+
|
|
4
|
+
# Timecop
|
|
5
|
+
# * Wrapper class for manipulating the extensions to the Time, Date, and DateTime objects
|
|
6
|
+
# * Allows us to "freeze" time in our Ruby applications.
|
|
7
|
+
# * Optionally allows time travel to simulate a running clock, such time is not technically frozen.
|
|
8
|
+
#
|
|
9
|
+
# This is very useful when your app's functionality is dependent on time (e.g.
|
|
10
|
+
# anything that might expire). This will allow us to alter the return value of
|
|
11
|
+
# Date.today, Time.now, and DateTime.now, such that our application code _never_ has to change.
|
|
12
|
+
class Timecop
|
|
13
|
+
include Singleton
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
private :instance
|
|
17
|
+
|
|
18
|
+
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
|
|
19
|
+
# This is particularly useful for writing test methods where the passage of time is critical to the business
|
|
20
|
+
# logic being tested. For example:
|
|
21
|
+
#
|
|
22
|
+
# joe = User.find(1)
|
|
23
|
+
# joe.purchase_home()
|
|
24
|
+
# assert !joe.mortgage_due?
|
|
25
|
+
# Timecop.freeze(2008, 10, 5) do
|
|
26
|
+
# assert joe.mortgage_due?
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# freeze and travel will respond to several different arguments:
|
|
30
|
+
# 1. Timecop.freeze(time_inst)
|
|
31
|
+
# 2. Timecop.freeze(datetime_inst)
|
|
32
|
+
# 3. Timecop.freeze(date_inst)
|
|
33
|
+
# 4. Timecop.freeze(offset_in_seconds)
|
|
34
|
+
# 5. Timecop.freeze(year, month, day, hour=0, minute=0, second=0)
|
|
35
|
+
# 6. Timecop.freeze() # Defaults to Time.now
|
|
36
|
+
#
|
|
37
|
+
# When a block is also passed, Time.now, DateTime.now and Date.today are all reset to their
|
|
38
|
+
# previous values after the block has finished executing. This allows us to nest multiple
|
|
39
|
+
# calls to Timecop.travel and have each block maintain it's concept of "now."
|
|
40
|
+
#
|
|
41
|
+
# The Process.clock_gettime call mocks both CLOCK::MONOTIC and CLOCK::REALTIME
|
|
42
|
+
#
|
|
43
|
+
# CLOCK::MONOTONIC works slightly differently than other clocks. This clock cannot move to a
|
|
44
|
+
# particular date/time. So the only option that changes this clock is #4 which will move the
|
|
45
|
+
# clock the requested offset. Otherwise the clock is frozen to the current tick.
|
|
46
|
+
#
|
|
47
|
+
# * Note: Timecop.freeze will actually freeze time. This can cause unanticipated problems if
|
|
48
|
+
# benchmark or other timing calls are executed, which implicitly expect Time to actually move
|
|
49
|
+
# forward.
|
|
50
|
+
#
|
|
51
|
+
# * Rails Users: Be especially careful when setting this in your development environment in a
|
|
52
|
+
# rails project. Generators will load your environment, including the migration generator,
|
|
53
|
+
# which will lead to files being generated with the timestamp set by the Timecop.freeze call
|
|
54
|
+
# in your dev environment
|
|
55
|
+
#
|
|
56
|
+
# Returns the value of the block if one is given, or the mocked time.
|
|
57
|
+
def freeze(*args, &block)
|
|
58
|
+
send_travel(:freeze, *args, &block)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
|
|
62
|
+
# See Timecop#freeze for a sample of how to use (same exact usage syntax)
|
|
63
|
+
#
|
|
64
|
+
# * Note: Timecop.travel will not freeze time (as opposed to Timecop.freeze). This is a particularly
|
|
65
|
+
# good candidate for use in environment files in rails projects.
|
|
66
|
+
#
|
|
67
|
+
# Returns the value of the block if one is given, or the mocked time.
|
|
68
|
+
def travel(*args, &block)
|
|
69
|
+
send_travel(:travel, *args, &block)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Allows you to run a block of code and "scale" a time throughout the execution of that block.
|
|
73
|
+
# The first argument is a scaling factor, for example:
|
|
74
|
+
# Timecop.scale(2) do
|
|
75
|
+
# ... time will 'go' twice as fast here
|
|
76
|
+
# end
|
|
77
|
+
# See Timecop#freeze for exact usage of the other arguments
|
|
78
|
+
#
|
|
79
|
+
# Returns the value of the block if one is given, or the mocked time.
|
|
80
|
+
def scale(*args, &block)
|
|
81
|
+
send_travel(:scale, *args, &block)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def baseline
|
|
85
|
+
instance.baseline
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def baseline=(baseline)
|
|
89
|
+
instance.baseline = baseline
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Reverts back to system's Time.now, Date.today and DateTime.now (if it exists) permamently when
|
|
93
|
+
# no block argument is given, or temporarily reverts back to the system's time temporarily for
|
|
94
|
+
# the given block.
|
|
95
|
+
def return(&block)
|
|
96
|
+
if block_given?
|
|
97
|
+
instance.return(&block)
|
|
98
|
+
else
|
|
99
|
+
instance.unmock!
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
alias :unfreeze :return
|
|
104
|
+
|
|
105
|
+
def return_to_baseline
|
|
106
|
+
instance.return_to_baseline
|
|
107
|
+
Time.now
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def top_stack_item #:nodoc:
|
|
111
|
+
instance.stack.last
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def safe_mode=(safe)
|
|
115
|
+
@safe_mode = safe
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def safe_mode?
|
|
119
|
+
@safe_mode ||= false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def thread_safe=(t)
|
|
123
|
+
instance.thread_safe = t
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def thread_safe
|
|
127
|
+
instance.thread_safe
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Returns whether or not Timecop is currently frozen
|
|
131
|
+
def frozen?
|
|
132
|
+
!instance.stack.empty? && instance.stack.last.mock_type == :freeze
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Returns whether or not Timecop is currently travelled
|
|
136
|
+
def travelled?
|
|
137
|
+
!instance.stack.empty? && instance.stack.last.mock_type == :travel
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Returns whether or not Timecop is currently scaled
|
|
141
|
+
def scaled?
|
|
142
|
+
!instance.stack.empty? && instance.stack.last.mock_type == :scale
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def mock_process_clock=(mock)
|
|
146
|
+
@mock_process_clock = mock
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def mock_process_clock?
|
|
150
|
+
@mock_process_clock ||= false
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
def send_travel(mock_type, *args, &block)
|
|
155
|
+
val = instance.travel(mock_type, *args, &block)
|
|
156
|
+
block_given? ? val : Time.now
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def baseline=(b)
|
|
161
|
+
set_baseline(b)
|
|
162
|
+
stack << TimeStackItem.new(:travel, b)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def baseline
|
|
166
|
+
if @thread_safe
|
|
167
|
+
Thread.current[:timecop_baseline]
|
|
168
|
+
else
|
|
169
|
+
@baseline
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def set_baseline(b)
|
|
174
|
+
if @thread_safe
|
|
175
|
+
Thread.current[:timecop_baseline] = b
|
|
176
|
+
else
|
|
177
|
+
@baseline = b
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def stack
|
|
182
|
+
if @thread_safe
|
|
183
|
+
Thread.current[:timecop_stack] ||= []
|
|
184
|
+
Thread.current[:timecop_stack]
|
|
185
|
+
else
|
|
186
|
+
@stack
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def set_stack(s)
|
|
191
|
+
if @thread_safe
|
|
192
|
+
Thread.current[:timecop_stack] = s
|
|
193
|
+
else
|
|
194
|
+
@stack = s
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def initialize #:nodoc:
|
|
199
|
+
@stack = []
|
|
200
|
+
@safe = nil
|
|
201
|
+
@thread_safe = false
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def thread_safe=(t)
|
|
205
|
+
initialize
|
|
206
|
+
@thread_safe = t
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def thread_safe
|
|
210
|
+
@thread_safe
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def travel(mock_type, *args, &block) #:nodoc:
|
|
214
|
+
raise SafeModeException if Timecop.safe_mode? && !block_given? && !@safe
|
|
215
|
+
|
|
216
|
+
stack_item = TimeStackItem.new(mock_type, *args)
|
|
217
|
+
|
|
218
|
+
stack_backup = stack.dup
|
|
219
|
+
stack << stack_item
|
|
220
|
+
|
|
221
|
+
if block_given?
|
|
222
|
+
safe_backup = @safe
|
|
223
|
+
@safe = true
|
|
224
|
+
begin
|
|
225
|
+
yield stack_item.time
|
|
226
|
+
ensure
|
|
227
|
+
stack.replace stack_backup
|
|
228
|
+
@safe = safe_backup
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def return(&block)
|
|
234
|
+
current_stack = stack
|
|
235
|
+
current_baseline = baseline
|
|
236
|
+
unmock!
|
|
237
|
+
yield
|
|
238
|
+
ensure
|
|
239
|
+
set_stack current_stack
|
|
240
|
+
set_baseline current_baseline
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def unmock! #:nodoc:
|
|
244
|
+
set_baseline nil
|
|
245
|
+
set_stack []
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def return_to_baseline
|
|
249
|
+
if baseline
|
|
250
|
+
set_stack [stack.shift]
|
|
251
|
+
else
|
|
252
|
+
unmock!
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
class SafeModeException < StandardError
|
|
257
|
+
def initialize
|
|
258
|
+
super "Safe mode is enabled, only calls passing a block are allowed."
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# This must be done after TimeCop is available
|
|
264
|
+
require File.join(File.dirname(__FILE__), "time_extensions")
|
metadata
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: nano-smart-lib
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andrey78
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-07-06 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: University research based on timecop
|
|
13
|
+
email:
|
|
14
|
+
- cakoc614@gmail.com
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- nano-smart-lib.gemspec
|
|
20
|
+
- timecop-0.9.11/LICENSE
|
|
21
|
+
- timecop-0.9.11/README.markdown
|
|
22
|
+
- timecop-0.9.11/Rakefile
|
|
23
|
+
- timecop-0.9.11/lib/timecop.rb
|
|
24
|
+
- timecop-0.9.11/lib/timecop/time_extensions.rb
|
|
25
|
+
- timecop-0.9.11/lib/timecop/time_stack_item.rb
|
|
26
|
+
- timecop-0.9.11/lib/timecop/timecop.rb
|
|
27
|
+
- timecop-0.9.11/lib/timecop/version.rb
|
|
28
|
+
homepage: https://rubygems.org/profiles/Andrey78
|
|
29
|
+
licenses:
|
|
30
|
+
- MIT
|
|
31
|
+
metadata:
|
|
32
|
+
source_code_uri: https://github.com/Andrey78/nano-smart-lib
|
|
33
|
+
rdoc_options: []
|
|
34
|
+
require_paths:
|
|
35
|
+
- lib
|
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
requirements: []
|
|
47
|
+
rubygems_version: 3.6.2
|
|
48
|
+
specification_version: 4
|
|
49
|
+
summary: Research test
|
|
50
|
+
test_files: []
|