minuteman 1.0.3 → 2.0.0.pre
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/.gems +3 -0
- data/.travis.yml +4 -3
- data/ORIGIN.md +21 -0
- data/README.md +115 -122
- data/Rakefile +3 -3
- data/SPEC.md +21 -0
- data/lib/minuteman.rb +88 -122
- data/lib/minuteman/analyzable.rb +96 -0
- data/lib/minuteman/analyzer.rb +21 -0
- data/lib/minuteman/configuration.rb +25 -0
- data/lib/minuteman/counter.rb +21 -0
- data/lib/minuteman/event.rb +12 -0
- data/lib/minuteman/lua/operations.lua +37 -0
- data/lib/minuteman/model.rb +36 -0
- data/lib/minuteman/result.rb +12 -0
- data/lib/minuteman/trigger.rb +4 -0
- data/lib/minuteman/user.rb +38 -0
- data/minuteman.gemspec +4 -5
- data/test/helper.rb +2 -0
- data/test/minuteman_bench.rb +72 -0
- data/test/minuteman_test.rb +204 -0
- metadata +44 -73
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -30
- data/lib/minuteman/bit_operations.rb +0 -97
- data/lib/minuteman/bit_operations/data.rb +0 -33
- data/lib/minuteman/bit_operations/operation.rb +0 -115
- data/lib/minuteman/bit_operations/plain.rb +0 -34
- data/lib/minuteman/bit_operations/result.rb +0 -15
- data/lib/minuteman/bit_operations/with_data.rb +0 -56
- data/lib/minuteman/keys_methods.rb +0 -23
- data/lib/minuteman/time_events.rb +0 -18
- data/lib/minuteman/time_span.rb +0 -36
- data/lib/minuteman/time_spans.rb +0 -7
- data/lib/minuteman/time_spans/day.rb +0 -17
- data/lib/minuteman/time_spans/hour.rb +0 -19
- data/lib/minuteman/time_spans/minute.rb +0 -19
- data/lib/minuteman/time_spans/month.rb +0 -17
- data/lib/minuteman/time_spans/week.rb +0 -18
- data/lib/minuteman/time_spans/year.rb +0 -17
- data/test/bench/minuteman_bench.rb +0 -37
- data/test/test_helper.rb +0 -9
- data/test/unit/minuteman_test.rb +0 -225
@@ -1,34 +0,0 @@
|
|
1
|
-
require "minuteman/keys_methods"
|
2
|
-
require "minuteman/bit_operations/result"
|
3
|
-
|
4
|
-
# Public: Minuteman core classs
|
5
|
-
#
|
6
|
-
class Minuteman
|
7
|
-
module BitOperations
|
8
|
-
# Public: The class to handle operations with others timespans
|
9
|
-
#
|
10
|
-
# type: The operation type
|
11
|
-
# timespan: The timespan to be permuted
|
12
|
-
# source_key: The original key to do the operation
|
13
|
-
#
|
14
|
-
class Plain < Struct.new(:type, :timespan, :source_key)
|
15
|
-
extend Forwardable
|
16
|
-
include KeysMethods
|
17
|
-
|
18
|
-
def_delegators :Minuteman, :redis, :safe
|
19
|
-
|
20
|
-
def call
|
21
|
-
events = if source_key == timespan
|
22
|
-
Array(source_key)
|
23
|
-
else
|
24
|
-
[source_key, timespan.key]
|
25
|
-
end
|
26
|
-
|
27
|
-
key = destination_key(type, events)
|
28
|
-
safe { redis.bitop(type, key, events) }
|
29
|
-
|
30
|
-
Result.new(key)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require "minuteman/bit_operations"
|
2
|
-
|
3
|
-
# Public: Minuteman core classs
|
4
|
-
#
|
5
|
-
class Minuteman
|
6
|
-
module BitOperations
|
7
|
-
# Public: The result of intersecting results
|
8
|
-
#
|
9
|
-
# key - The key where the result it's stored
|
10
|
-
#
|
11
|
-
class Result < Struct.new(:key)
|
12
|
-
include BitOperations
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require "minuteman/keys_methods"
|
2
|
-
require "minuteman/bit_operations/data"
|
3
|
-
|
4
|
-
# Public: Minuteman core classs
|
5
|
-
#
|
6
|
-
class Minuteman
|
7
|
-
module BitOperations
|
8
|
-
# Public: The class to handle operations with datasets
|
9
|
-
#
|
10
|
-
# type: The operation type
|
11
|
-
# data: The data to be permuted
|
12
|
-
# source_key: The original key to do the operation
|
13
|
-
#
|
14
|
-
class WithData < Struct.new(:type, :data, :source_key)
|
15
|
-
extend Forwardable
|
16
|
-
include KeysMethods
|
17
|
-
|
18
|
-
def_delegators :Minuteman, :redis, :safe
|
19
|
-
|
20
|
-
def call
|
21
|
-
key = destination_key("data-#{type}", normalized_data)
|
22
|
-
|
23
|
-
if !safe { redis.exists(key) }
|
24
|
-
intersected_data.each { |id| safe { redis.setbit(key, id, 1) } }
|
25
|
-
end
|
26
|
-
|
27
|
-
Data.new(key, intersected_data)
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
# Private: Normalized data
|
33
|
-
#
|
34
|
-
def normalized_data
|
35
|
-
Array(data)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Private: Defines command to get executed based on the type
|
39
|
-
#
|
40
|
-
def command
|
41
|
-
case type
|
42
|
-
when "AND" then :select
|
43
|
-
when "MINUS" then :reject
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Private: The intersected data depending on the command executed
|
48
|
-
#
|
49
|
-
def intersected_data
|
50
|
-
normalized_data.send(command) do |id|
|
51
|
-
Minuteman.redis.getbit(source_key, id) == 1
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# Public: Minuteman core classs
|
2
|
-
#
|
3
|
-
class Minuteman
|
4
|
-
module KeysMethods
|
5
|
-
BIT_OPERATION_PREFIX = "bitop"
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
# Private: The destination key for the operation
|
10
|
-
#
|
11
|
-
# type - The bitwise operation
|
12
|
-
# events - The events to permuted
|
13
|
-
#
|
14
|
-
def destination_key(type, events)
|
15
|
-
[
|
16
|
-
Minuteman::PREFIX,
|
17
|
-
BIT_OPERATION_PREFIX,
|
18
|
-
type,
|
19
|
-
events.join("-")
|
20
|
-
].join("_")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require "minuteman/time_spans"
|
2
|
-
|
3
|
-
# Public: Minuteman core classs
|
4
|
-
#
|
5
|
-
class Minuteman
|
6
|
-
module TimeEvents
|
7
|
-
# Public: Helper to get all the time trackers ready
|
8
|
-
#
|
9
|
-
# event_name - The event to be tracked
|
10
|
-
# date - A given Time object
|
11
|
-
#
|
12
|
-
def self.start(time_spans, event_name, time)
|
13
|
-
time_spans.map do |t|
|
14
|
-
t.new(event_name, time)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/minuteman/time_span.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require "minuteman/bit_operations"
|
2
|
-
|
3
|
-
# Public: Minuteman core classs
|
4
|
-
#
|
5
|
-
class Minuteman
|
6
|
-
# Public: The timespan class. All the time span classes inherit from this one
|
7
|
-
#
|
8
|
-
class TimeSpan
|
9
|
-
include BitOperations
|
10
|
-
|
11
|
-
attr_reader :key
|
12
|
-
|
13
|
-
DATE_FORMAT = "%s-%02d-%02d"
|
14
|
-
TIME_FORMAT = "%02d:%02d"
|
15
|
-
|
16
|
-
# Public: Initializes the base TimeSpan class
|
17
|
-
#
|
18
|
-
# event_name - The event to be tracked
|
19
|
-
# date - A given Time object
|
20
|
-
#
|
21
|
-
def initialize(event_name, date)
|
22
|
-
@key = build_key(event_name, time_format(date))
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
# Private: The redis key that's going to be used
|
28
|
-
#
|
29
|
-
# event_name - The event to be tracked
|
30
|
-
# date - A given Time object
|
31
|
-
#
|
32
|
-
def build_key(event_name, date)
|
33
|
-
[Minuteman::PREFIX, event_name, date.join("-")].join("_")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/minuteman/time_spans.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# Public: Minuteman core classs
|
2
|
-
#
|
3
|
-
class Minuteman
|
4
|
-
# Public: Day TimeSpan class
|
5
|
-
#
|
6
|
-
class Day < TimeSpan
|
7
|
-
private
|
8
|
-
|
9
|
-
# Private: The format that's going the be used for the date part of the key
|
10
|
-
#
|
11
|
-
# date - A given Time object
|
12
|
-
#
|
13
|
-
def time_format(date)
|
14
|
-
[DATE_FORMAT % [date.year, date.month, date.day]]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# Public: Minuteman core classs
|
2
|
-
#
|
3
|
-
class Minuteman
|
4
|
-
# Public: Hour TimeSpan class
|
5
|
-
#
|
6
|
-
class Hour < TimeSpan
|
7
|
-
private
|
8
|
-
|
9
|
-
# Private: The format that's going the be used for the date part of the key
|
10
|
-
#
|
11
|
-
# date - A given Time object
|
12
|
-
#
|
13
|
-
def time_format(date)
|
14
|
-
full_date = DATE_FORMAT % [date.year, date.month, date.day]
|
15
|
-
time = TIME_FORMAT % [date.hour, 0]
|
16
|
-
[full_date + " " + time]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# Public: Minuteman core classs
|
2
|
-
#
|
3
|
-
class Minuteman
|
4
|
-
# Public: Minute TimeSpan class
|
5
|
-
#
|
6
|
-
class Minute < TimeSpan
|
7
|
-
private
|
8
|
-
|
9
|
-
# Private: The format that's going the be used for the date part of the key
|
10
|
-
#
|
11
|
-
# date - A given Time object
|
12
|
-
#
|
13
|
-
def time_format(date)
|
14
|
-
full_date = DATE_FORMAT % [date.year, date.month, date.day]
|
15
|
-
time = TIME_FORMAT % [date.hour, date.min]
|
16
|
-
[full_date + " " + time]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# Public: Minuteman core classs
|
2
|
-
#
|
3
|
-
class Minuteman
|
4
|
-
# Public: Month TimeSpan class
|
5
|
-
#
|
6
|
-
class Month < TimeSpan
|
7
|
-
private
|
8
|
-
|
9
|
-
# Private: The format that's going the be used for the date part of the key
|
10
|
-
#
|
11
|
-
# date - A given Time object
|
12
|
-
#
|
13
|
-
def time_format(date)
|
14
|
-
[date.year, "%02d" % date.month]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# Public: Minuteman core classs
|
2
|
-
#
|
3
|
-
class Minuteman
|
4
|
-
# Public: Month TimeSpan class
|
5
|
-
#
|
6
|
-
class Week < TimeSpan
|
7
|
-
private
|
8
|
-
|
9
|
-
# Private: The format that's going the be used for the date part of the key
|
10
|
-
#
|
11
|
-
# date - A given Time object
|
12
|
-
#
|
13
|
-
def time_format(date)
|
14
|
-
week = date.strftime("%W")
|
15
|
-
[date.year, "W" + week]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# Public: Minuteman core classs
|
2
|
-
#
|
3
|
-
class Minuteman
|
4
|
-
# Public: Year TimeSpan class
|
5
|
-
#
|
6
|
-
class Year < TimeSpan
|
7
|
-
private
|
8
|
-
|
9
|
-
# Private: The format that's going the be used for the date part of the key
|
10
|
-
#
|
11
|
-
# date - A given Time object
|
12
|
-
#
|
13
|
-
def time_format(date)
|
14
|
-
[date.year]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require_relative "../test_helper"
|
2
|
-
require "minitest/benchmark"
|
3
|
-
|
4
|
-
describe Minuteman do
|
5
|
-
before do
|
6
|
-
today = Time.now.utc
|
7
|
-
last_week = today - (3600 * 24 * 7)
|
8
|
-
|
9
|
-
@analytics = Minuteman.new
|
10
|
-
@analytics.track("login", 12)
|
11
|
-
@analytics.track("login", [2, 42])
|
12
|
-
@analytics.track("login:successful", 567, last_week)
|
13
|
-
|
14
|
-
@week_events = @analytics.week("login")
|
15
|
-
@last_week_events = @analytics.week("login", last_week)
|
16
|
-
@last_week_events2 = @analytics.month("login:successful", last_week)
|
17
|
-
end
|
18
|
-
|
19
|
-
bench_performance_constant("AND") { @week_events & @last_week_events }
|
20
|
-
bench_performance_constant("OR") { @week_events | @last_week_events }
|
21
|
-
bench_performance_constant("XOR") { @week_events ^ @last_week_events }
|
22
|
-
bench_performance_constant("NOT") { ~@week_events }
|
23
|
-
bench_performance_constant("MINUS") { @week_events - @last_week_events }
|
24
|
-
|
25
|
-
bench_performance_constant "complex operations" do
|
26
|
-
@week_events & (@last_week_events ^ @last_week_events2)
|
27
|
-
end
|
28
|
-
|
29
|
-
bench_performance_constant "intersections using cache" do
|
30
|
-
5.times { @week_events & [2, 12, 43] }
|
31
|
-
end
|
32
|
-
|
33
|
-
bench_performance_constant "intersections not using cache" do
|
34
|
-
@analytics.options[:cache] = false
|
35
|
-
5.times { @week_events & [2, 12, 43] }
|
36
|
-
end
|
37
|
-
end
|
data/test/test_helper.rb
DELETED
data/test/unit/minuteman_test.rb
DELETED
@@ -1,225 +0,0 @@
|
|
1
|
-
require_relative "../test_helper"
|
2
|
-
|
3
|
-
describe Minuteman do
|
4
|
-
Given(:analytics) { Minuteman.new }
|
5
|
-
|
6
|
-
after { analytics.reset_all }
|
7
|
-
|
8
|
-
context "configuration" do
|
9
|
-
Then { analytics.redis }
|
10
|
-
Then { analytics.options[:cache] == true }
|
11
|
-
|
12
|
-
context "switching options" do
|
13
|
-
Given(:minuteman) { Minuteman.new }
|
14
|
-
|
15
|
-
When { minuteman.options[:cache] = false }
|
16
|
-
Then { minuteman.options[:cache] == false }
|
17
|
-
end
|
18
|
-
|
19
|
-
context "changing time spans" do
|
20
|
-
Given(:time_spans) { %w[year month day hour] }
|
21
|
-
Given(:minuteman) { Minuteman.new(time_spans: time_spans) }
|
22
|
-
|
23
|
-
When { minuteman.track("login", 12) }
|
24
|
-
|
25
|
-
Then { minuteman.respond_to?(:year) }
|
26
|
-
Then { minuteman.respond_to?(:month) }
|
27
|
-
Then { minuteman.respond_to?(:day) }
|
28
|
-
Then { minuteman.respond_to?(:hour) }
|
29
|
-
|
30
|
-
Then { !minuteman.respond_to?(:minute) }
|
31
|
-
Then { !minuteman.respond_to?(:week) }
|
32
|
-
|
33
|
-
Then { minuteman.redis.keys.size == 4 }
|
34
|
-
Then { minuteman.options[:time_spans] == time_spans }
|
35
|
-
end
|
36
|
-
|
37
|
-
context "fail silently" do
|
38
|
-
Given(:minuteman) { Minuteman.new(silent: true, redis: { port: 1234 }) }
|
39
|
-
When(:result) { minuteman.track("test", 1) }
|
40
|
-
Then { result == nil }
|
41
|
-
end
|
42
|
-
|
43
|
-
context "fail loudly" do
|
44
|
-
Given(:minuteman) { Minuteman.new(redis: { port: 1234 }) }
|
45
|
-
When(:result) { minuteman.track("test", 1) }
|
46
|
-
Then { result == Failure(Redis::CannotConnectError) }
|
47
|
-
end
|
48
|
-
|
49
|
-
context "changing Redis connection" do
|
50
|
-
Given(:redis) { Redis.new }
|
51
|
-
Then { Minuteman.redis != redis }
|
52
|
-
|
53
|
-
context "return the correct connection" do
|
54
|
-
When(:minuteman) { Minuteman.new(redis: redis) }
|
55
|
-
|
56
|
-
Then { minuteman.redis == redis }
|
57
|
-
end
|
58
|
-
|
59
|
-
context "switching the connection" do
|
60
|
-
Given(:minuteman) { Minuteman.new }
|
61
|
-
When { minuteman.redis = redis }
|
62
|
-
Then { redis == Minuteman.redis }
|
63
|
-
end
|
64
|
-
|
65
|
-
context "using Redis::Namespace" do
|
66
|
-
Given(:namespace) { Redis::Namespace.new(:ns, redis: Redis.new) }
|
67
|
-
Given(:minuteman) { Minuteman.new(redis: namespace) }
|
68
|
-
|
69
|
-
Then { minuteman.redis == namespace }
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
context "event tracking" do
|
75
|
-
Given(:today) { Time.now.utc }
|
76
|
-
Given(:last_month) { today - (3600 * 24 * 30) }
|
77
|
-
Given(:last_week) { today - (3600 * 24 * 7) }
|
78
|
-
Given(:last_minute) { today - 120 }
|
79
|
-
|
80
|
-
Given(:year_events) { analytics.year("login", today) }
|
81
|
-
Given(:week_events) { analytics.week("login", today) }
|
82
|
-
Given(:month_events) { analytics.month("login", today) }
|
83
|
-
Given(:day_events) { analytics.day("login", today) }
|
84
|
-
Given(:hour_events) { analytics.hour("login", today) }
|
85
|
-
Given(:minute_events) { analytics.minute("login", today) }
|
86
|
-
Given(:last_week_events) { analytics.week("login", last_week) }
|
87
|
-
Given(:last_minute_events) { analytics.minute("login", last_minute) }
|
88
|
-
Given(:last_month_events) { analytics.month("login:successful", last_month) }
|
89
|
-
|
90
|
-
before do
|
91
|
-
analytics.track("login", 12)
|
92
|
-
analytics.track("login", [2, 42])
|
93
|
-
analytics.track("login", 2, last_week)
|
94
|
-
analytics.track("login:successful", 567, last_month)
|
95
|
-
end
|
96
|
-
|
97
|
-
Then { analytics.events.size == 2 }
|
98
|
-
Then { year_events.length == 3 }
|
99
|
-
Then { week_events.length == 3 }
|
100
|
-
Then { last_week_events.length == 1 }
|
101
|
-
Then { last_month_events.length == 1 }
|
102
|
-
|
103
|
-
context "reseting" do
|
104
|
-
before { analytics.reset_all }
|
105
|
-
Then { analytics.events.size == 0 }
|
106
|
-
|
107
|
-
context "bit operations" do
|
108
|
-
before { week_events & last_week_events }
|
109
|
-
|
110
|
-
When { analytics.reset_operations_cache }
|
111
|
-
Then { analytics.operations.size == 0 }
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
context "on a given time" do
|
116
|
-
Then { year_events.length == 3 }
|
117
|
-
Then { week_events.length == 3 }
|
118
|
-
|
119
|
-
Then { week_events.include?(12, 2, 1) == [true, true, false] }
|
120
|
-
Then { year_events.include?(12) }
|
121
|
-
Then { month_events.include?(12) }
|
122
|
-
Then { day_events.include?(12) }
|
123
|
-
Then { hour_events.include?(12) }
|
124
|
-
Then { minute_events.include?(12) }
|
125
|
-
|
126
|
-
Then { last_week_events.include?(2) }
|
127
|
-
Then { !month_events.include?(5) }
|
128
|
-
Then { !last_minute_events.include?(12) }
|
129
|
-
Then { last_month_events.include?(567) }
|
130
|
-
end
|
131
|
-
|
132
|
-
context "listing events" do
|
133
|
-
Then { analytics.events.size == 2 }
|
134
|
-
Then { analytics.events.sort == ["login", "login:successful"] }
|
135
|
-
end
|
136
|
-
|
137
|
-
context "composing" do
|
138
|
-
context "using AND" do
|
139
|
-
Given(:and_operation) { week_events & last_week_events }
|
140
|
-
|
141
|
-
Then { week_events.include?(2) }
|
142
|
-
Then { week_events.include?(12) }
|
143
|
-
|
144
|
-
Then { last_week_events.include?(2) }
|
145
|
-
Then { !last_week_events.include?(12) }
|
146
|
-
|
147
|
-
Then { !and_operation.include?(12) }
|
148
|
-
Then { and_operation.include?(2) }
|
149
|
-
Then { and_operation.length == 1 }
|
150
|
-
end
|
151
|
-
|
152
|
-
context "using OR" do
|
153
|
-
Given(:or_operation) { week_events | last_week_events }
|
154
|
-
|
155
|
-
Then { week_events.include?(2) }
|
156
|
-
Then { last_week_events.include?(2) }
|
157
|
-
Then { !last_week_events.include?(12) }
|
158
|
-
|
159
|
-
Then { or_operation.include?(12) }
|
160
|
-
Then { or_operation.include?(2) }
|
161
|
-
Then { or_operation.length == 3 }
|
162
|
-
end
|
163
|
-
|
164
|
-
context "using NOT" do
|
165
|
-
Given(:not_operation) { ~week_events }
|
166
|
-
|
167
|
-
Then { week_events.include?(2) }
|
168
|
-
Then { week_events.include?(12) }
|
169
|
-
|
170
|
-
Then { !not_operation.include?(12) }
|
171
|
-
Then { !not_operation.include?(2) }
|
172
|
-
end
|
173
|
-
|
174
|
-
context "using OR alias (+)" do
|
175
|
-
Given(:or_operation) { week_events + last_week_events }
|
176
|
-
|
177
|
-
Then { week_events.include?(2) }
|
178
|
-
Then { last_week_events.include?(2) }
|
179
|
-
Then { !last_week_events.include?(12) }
|
180
|
-
|
181
|
-
Then { or_operation.include?(12) }
|
182
|
-
Then { or_operation.include?(2) }
|
183
|
-
Then { or_operation.length == 3 }
|
184
|
-
end
|
185
|
-
|
186
|
-
context "using MINUS" do
|
187
|
-
Given(:substract_operation) { year_events - week_events }
|
188
|
-
|
189
|
-
Then { week_events.include?(2) }
|
190
|
-
Then { year_events.include?(2) }
|
191
|
-
Then { !substract_operation.include?(2) }
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
context "composing multiple operations" do
|
196
|
-
Given(:multi_operation) { week_events & last_week_events | year_events }
|
197
|
-
Then { multi_operation.is_a?(Minuteman::BitOperations::Result) }
|
198
|
-
end
|
199
|
-
|
200
|
-
context "composing against arrays" do
|
201
|
-
context "using AND returns the intersection" do
|
202
|
-
Given(:ids) { week_events & [2, 12, 43] }
|
203
|
-
|
204
|
-
Then { ids.is_a?(Minuteman::BitOperations::Data) }
|
205
|
-
Then { ids == [2, 12] }
|
206
|
-
end
|
207
|
-
|
208
|
-
context "using MINUS returns the difference" do
|
209
|
-
Given(:ids) { week_events - [2, 12, 43] }
|
210
|
-
|
211
|
-
Then { ids.is_a?(Minuteman::BitOperations::Data) }
|
212
|
-
Then { ids == [43] }
|
213
|
-
end
|
214
|
-
|
215
|
-
context "returns an object that behaves like Array" do
|
216
|
-
Given(:ids) { week_events & [2, 12, 43] }
|
217
|
-
|
218
|
-
Then { ids.each.is_a?(Enumerator) }
|
219
|
-
Then { ids.map.is_a?(Enumerator) }
|
220
|
-
Then { ids.size == 2 }
|
221
|
-
end
|
222
|
-
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|