plunk 0.3.2 → 0.3.3
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 +4 -4
- data/Gemfile.lock +3 -1
- data/README.md +64 -20
- data/lib/plunk/helper.rb +18 -1
- data/lib/plunk/parser.rb +32 -7
- data/lib/plunk/transformer.rb +55 -12
- data/plunk.gemspec +2 -1
- data/spec/limit_spec.rb +11 -0
- data/spec/regexp_spec.rb +18 -6
- data/spec/window_spec.rb +42 -0
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9783fb61da735628ac2266ff16fd4234d146bed
|
4
|
+
data.tar.gz: 8fa8d01bffed0cc5351afef868a2e22caa3ddf88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aaf0493c53bfee8441676b7e72697fb72d47e32b5e6abd8e505e6ef89483a7976bc6ec3a5fb5b34b5959fff0a4d5074cb836b9acde565417737589c704c0fb54
|
7
|
+
data.tar.gz: 3767a5c241aa94a9c55faef62742f6e57862377cb2e662cc0c58cd7a952dd1ac5716f3ddea6a894adf73f806c0db5481c95e4f99c1804033a59d9f1875a7a2bf
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
plunk (0.3.
|
4
|
+
plunk (0.3.2)
|
5
5
|
activesupport (~> 4.0, >= 4.0.0)
|
6
|
+
chronic (~> 0.10, >= 0.10.0)
|
6
7
|
elasticsearch (~> 0.4, >= 0.4.3)
|
7
8
|
json (~> 1.8, >= 1.8.0)
|
8
9
|
parslet (~> 1.5, >= 1.5.0)
|
@@ -18,6 +19,7 @@ GEM
|
|
18
19
|
tzinfo (~> 0.3.37)
|
19
20
|
atomic (1.1.14)
|
20
21
|
blankslate (2.1.2.4)
|
22
|
+
chronic (0.10.2)
|
21
23
|
diff-lcs (1.2.5)
|
22
24
|
elasticsearch (0.4.3)
|
23
25
|
elasticsearch-api (= 0.4.3)
|
data/README.md
CHANGED
@@ -5,43 +5,82 @@ Human-friendly query language for Elasticsearch
|
|
5
5
|
|
6
6
|
## About
|
7
7
|
|
8
|
-
Plunk is a ruby gem to take a human-friendly search command and
|
9
|
-
to
|
10
|
-
commands, but the
|
8
|
+
Plunk is a ruby gem to take a human-friendly, one-line search command and
|
9
|
+
translate it to full-fledged JSON to send to Elasticsearch. Currently it only
|
10
|
+
supports a few commands, but the goal is to support a large subset of what
|
11
|
+
Elasticsearch offers.
|
11
12
|
|
12
13
|
## Installation
|
13
14
|
```
|
14
15
|
gem install plunk
|
15
16
|
```
|
16
17
|
|
18
|
+
Plunk uses [Parslet](https://github.com/kschiess/parslet) to first parse your
|
19
|
+
query, and then [Elasticsearch's official ruby library](https://github.com/elasticsearch/elasticsearch-ruby)
|
20
|
+
to send it to Elasticsearch.
|
21
|
+
|
17
22
|
## Usage
|
18
23
|
```ruby
|
19
24
|
require 'plunk'
|
20
25
|
|
21
|
-
#
|
22
|
-
#
|
26
|
+
#
|
27
|
+
# Configuration is required before using Plunk
|
28
|
+
#
|
29
|
+
# Elasticsearch_options accepts the same params as Elasticsearch::Client
|
30
|
+
# from the elasticsearch-ruby library
|
23
31
|
Plunk.configure do |config|
|
24
32
|
config.elasticsearch_options = { host: 'localhost' }
|
25
33
|
end
|
26
34
|
|
27
|
-
#
|
28
|
-
|
35
|
+
# Restrict timeframe to last 1 week and match documents with _type=syslog
|
36
|
+
# s = seconds
|
37
|
+
# m = minutes
|
38
|
+
# h = hours
|
39
|
+
# d = days
|
40
|
+
# w = weeks
|
41
|
+
# All times in Plunk are converted to UTC
|
42
|
+
Plunk.search 'last 1w AND _type = syslog'
|
43
|
+
|
44
|
+
# The ```window``` command can also be used to filter by time
|
45
|
+
Plunk.search 'window -2d to -1d'
|
46
|
+
|
47
|
+
# Plunk tries to parse the date with Chronic, so this works too. Note the
|
48
|
+
# double quotes around the time string. This is needed if it contains a space.
|
49
|
+
Plunk.search 'window "last monday" to "last thursday"'
|
50
|
+
|
51
|
+
# Of course, absolute dates are supported as well. Date format is American style
|
52
|
+
# e.g. MM/DD/YY
|
53
|
+
Plunk.search 'window 3/14/12 to 3/15/12'
|
54
|
+
|
55
|
+
# Use double quotes to wrap space-containing strings
|
56
|
+
Plunk.search 'http.header = "UserAgent: Mozilla/5.0"'
|
57
|
+
|
58
|
+
# Commands are joined using parenthesized booleans
|
59
|
+
Plunk.search '(last 1h AND severity = 5) OR (last 1w AND severity = 3)'
|
29
60
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
|
33
|
-
Plunk.search '
|
61
|
+
# "AND" is aliased to "and" and "&". Similarly, "OR" is aliased to "or" and "|".
|
62
|
+
# The following queries are identical to one above
|
63
|
+
Plunk.search '(last 1h and severity = 5) or (last 1w and severity = 3)'
|
64
|
+
Plunk.search '(last 1h & severity = 5) | (last 1w & severity = 3)'
|
34
65
|
|
35
|
-
#
|
36
|
-
Plunk.search '
|
66
|
+
# Use the NOT keyword to negate the following command or boolean chain
|
67
|
+
Plunk.search 'NOT message = Error'
|
68
|
+
|
69
|
+
# Like AND and OR, "NOT" is aliased to "not" and "~"
|
70
|
+
Plunk.search 'not message = Error'
|
71
|
+
Plunk.search '~ message = Error'
|
72
|
+
|
73
|
+
# Regexp is supported as well
|
74
|
+
Plunk.search 'http.headers = /.*User-Agent: Mozilla.*/ OR http.headers = /.*application\/json.*/'
|
37
75
|
```
|
38
76
|
|
39
77
|
|
40
78
|
## Translation
|
41
79
|
|
42
|
-
Plunk takes your
|
80
|
+
Under the hood, Plunk takes your query and translates it to
|
81
|
+
Elasticsearch-compatible JSON. For example,
|
43
82
|
|
44
|
-
```last 24h _type=syslog```
|
83
|
+
```last 24h & _type=syslog```
|
45
84
|
|
46
85
|
gets translated to:
|
47
86
|
|
@@ -49,11 +88,6 @@ gets translated to:
|
|
49
88
|
{
|
50
89
|
"query": {
|
51
90
|
"filtered": {
|
52
|
-
"query": {
|
53
|
-
"query_string": {
|
54
|
-
"query": "_type:syslog"
|
55
|
-
}
|
56
|
-
},
|
57
91
|
"filter": {
|
58
92
|
"and": [
|
59
93
|
{
|
@@ -63,6 +97,13 @@ gets translated to:
|
|
63
97
|
"lte": "2013-08-24T05:43:13.770Z"
|
64
98
|
}
|
65
99
|
}
|
100
|
+
},
|
101
|
+
{
|
102
|
+
"query": {
|
103
|
+
"query_string": {
|
104
|
+
"query": "_type:syslog"
|
105
|
+
}
|
106
|
+
}
|
66
107
|
}
|
67
108
|
]
|
68
109
|
}
|
@@ -70,3 +111,6 @@ gets translated to:
|
|
70
111
|
}
|
71
112
|
}
|
72
113
|
```
|
114
|
+
|
115
|
+
In general, commands are combined into a single filter using Elasticsearch's,
|
116
|
+
```and```, ```or```, and ```not``` filters.
|
data/lib/plunk/helper.rb
CHANGED
@@ -30,17 +30,34 @@ module Plunk
|
|
30
30
|
}
|
31
31
|
end
|
32
32
|
|
33
|
+
def self.limit_builder(limit)
|
34
|
+
{
|
35
|
+
limit: {
|
36
|
+
value: limit
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
33
41
|
def self.range_builder(range_min, range_max)
|
34
42
|
{
|
35
43
|
range: {
|
36
44
|
Plunk.timestamp_field => {
|
37
45
|
gte: range_min,
|
38
|
-
|
46
|
+
lte: range_max
|
39
47
|
}
|
40
48
|
}
|
41
49
|
}
|
42
50
|
end
|
43
51
|
|
52
|
+
def self.regexp_builder(field, regexp, flags=nil)
|
53
|
+
{
|
54
|
+
regexp: {
|
55
|
+
field => regexp,
|
56
|
+
flags: flags || 'ALL'
|
57
|
+
}
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
44
61
|
def self.time_query_to_timestamp(int_quantity, quantifier)
|
45
62
|
case quantifier
|
46
63
|
when 's'
|
data/lib/plunk/parser.rb
CHANGED
@@ -13,7 +13,9 @@ module Plunk
|
|
13
13
|
rule(:space?) { space.maybe }
|
14
14
|
|
15
15
|
# Numbers
|
16
|
-
rule(:
|
16
|
+
rule(:positive_integer) { digit.repeat(1) >> space? }
|
17
|
+
rule(:negative_integer) { str('-') >> positive_integer }
|
18
|
+
rule(:integer) { negative_integer | positive_integer }
|
17
19
|
rule(:float) {
|
18
20
|
str('-').maybe >> digit.repeat(1) >> str('.') >> digit.repeat(1) >> space?
|
19
21
|
}
|
@@ -62,6 +64,16 @@ module Plunk
|
|
62
64
|
rule(:rhs) {
|
63
65
|
regexp | query_value
|
64
66
|
}
|
67
|
+
rule(:chronic_time) {
|
68
|
+
string | match('[^\s]').repeat
|
69
|
+
}
|
70
|
+
rule(:relative_time) {
|
71
|
+
integer.as(:quantity) >>
|
72
|
+
match('s|m|h|d|w').as(:quantifier)
|
73
|
+
}
|
74
|
+
rule(:absolute_time) {
|
75
|
+
datetime.as(:datetime) | chronic_time.as(:chronic_time)
|
76
|
+
}
|
65
77
|
|
66
78
|
# Field = Value
|
67
79
|
rule(:field_value) {
|
@@ -72,20 +84,31 @@ module Plunk
|
|
72
84
|
|
73
85
|
# Value-only
|
74
86
|
rule(:value_only) {
|
75
|
-
|
87
|
+
query_value.as(:value)
|
88
|
+
}
|
89
|
+
|
90
|
+
# Window
|
91
|
+
rule(:window) {
|
92
|
+
str('window') >>
|
93
|
+
space >>
|
94
|
+
(relative_time | absolute_time).as(:window_start) >>
|
95
|
+
space >> str('to') >> space >>
|
96
|
+
(relative_time | absolute_time).as(:window_end)
|
97
|
+
}
|
98
|
+
|
99
|
+
# Limit
|
100
|
+
rule(:limit) {
|
101
|
+
str('limit') >> space >> positive_integer.as(:limit)
|
76
102
|
}
|
77
103
|
|
78
104
|
# Regexp
|
79
105
|
rule(:regexp) {
|
80
|
-
str('/') >> (str('\/') | match('[^/]')).repeat >> str('/')
|
106
|
+
str('/') >> (str('\/') | match('[^/]')).repeat.as(:regexp) >> str('/')
|
81
107
|
}
|
82
108
|
|
83
109
|
# Last
|
84
110
|
rule(:last) {
|
85
|
-
str('last') >>
|
86
|
-
space >>
|
87
|
-
integer.as(:quantity) >>
|
88
|
-
match('s|m|h|d|w').as(:quantifier)
|
111
|
+
(str('last') >> space >> relative_time).as(:last)
|
89
112
|
}
|
90
113
|
|
91
114
|
# Subsearch
|
@@ -101,7 +124,9 @@ module Plunk
|
|
101
124
|
# NOTE: order matters!
|
102
125
|
rule(:command) {
|
103
126
|
(
|
127
|
+
window |
|
104
128
|
last |
|
129
|
+
limit |
|
105
130
|
field_value |
|
106
131
|
value_only
|
107
132
|
).as(:command) >> space?
|
data/lib/plunk/transformer.rb
CHANGED
@@ -1,41 +1,84 @@
|
|
1
1
|
require 'parslet'
|
2
|
+
require 'chronic'
|
2
3
|
|
3
4
|
module Plunk
|
4
5
|
class Transformer < Parslet::Transform
|
6
|
+
# Base
|
7
|
+
rule(command: subtree(:command)) do
|
8
|
+
command
|
9
|
+
end
|
10
|
+
|
5
11
|
# Field = Value
|
6
|
-
rule(
|
12
|
+
rule(
|
7
13
|
field: simple(:field),
|
8
14
|
value: simple(:value)
|
9
|
-
|
15
|
+
) do
|
10
16
|
Helper.query_builder(
|
11
17
|
String(field) + ":" + String(value)
|
12
18
|
)
|
13
19
|
end
|
14
20
|
|
21
|
+
# Limit
|
22
|
+
rule(limit: simple(:limit)) do
|
23
|
+
Helper.limit_builder(Integer(limit))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Regexp
|
27
|
+
rule(
|
28
|
+
field: simple(:field),
|
29
|
+
value: {
|
30
|
+
regexp: simple(:regexp)
|
31
|
+
}
|
32
|
+
) do
|
33
|
+
Helper.regexp_builder(String(field), String(regexp))
|
34
|
+
end
|
35
|
+
|
15
36
|
# Value-only
|
16
|
-
rule(
|
37
|
+
rule(value: simple(:value)) do
|
17
38
|
Helper.query_builder(String(value))
|
18
39
|
end
|
19
40
|
|
20
|
-
|
41
|
+
# Last
|
42
|
+
rule(last: subtree(:last)) do
|
43
|
+
start_time = last
|
44
|
+
end_time = Helper.timestamp_format(Time.now)
|
45
|
+
|
46
|
+
Helper.range_builder(start_time, end_time)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Window
|
50
|
+
rule(
|
51
|
+
window_start: subtree(:window_start),
|
52
|
+
window_end: subtree(:window_end)
|
53
|
+
) do
|
54
|
+
Helper.range_builder(window_start, window_end)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Time parts
|
58
|
+
rule(datetime: simple(:datetime)) do
|
59
|
+
String(datetime)
|
60
|
+
end
|
61
|
+
rule(
|
21
62
|
quantity: simple(:quantity),
|
22
63
|
quantifier: simple(:quantifier)
|
23
|
-
|
24
|
-
|
25
|
-
Integer(quantity),
|
64
|
+
) do
|
65
|
+
timestamp = Helper.time_query_to_timestamp(
|
66
|
+
Integer(quantity).abs, # last -1h same as last 1h
|
26
67
|
String(quantifier)
|
27
68
|
)
|
28
69
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
Helper.
|
70
|
+
Helper.timestamp_format timestamp
|
71
|
+
end
|
72
|
+
rule(chronic_time: simple(:chronic_time)) do
|
73
|
+
Helper.timestamp_format Chronic.parse(chronic_time)
|
33
74
|
end
|
34
75
|
|
35
|
-
|
76
|
+
# Negate
|
77
|
+
rule(negate: subtree(:not)) do
|
36
78
|
{ not: negate }
|
37
79
|
end
|
38
80
|
|
81
|
+
# Command joining
|
39
82
|
rule(:or => {
|
40
83
|
left: subtree(:left),
|
41
84
|
right: subtree(:right)
|
data/plunk.gemspec
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "plunk"
|
3
|
-
s.version = "0.3.
|
3
|
+
s.version = "0.3.3"
|
4
4
|
s.add_runtime_dependency "json", "~> 1.8", ">= 1.8.0"
|
5
5
|
s.add_runtime_dependency "parslet", "~> 1.5", ">= 1.5.0"
|
6
6
|
s.add_runtime_dependency "elasticsearch", "~> 0.4", ">= 0.4.3"
|
7
7
|
s.add_runtime_dependency "activesupport", "~> 4.0", ">= 4.0.0"
|
8
|
+
s.add_runtime_dependency "chronic", "~> 0.10", ">= 0.10.0"
|
8
9
|
s.add_development_dependency "rspec", "~> 2.0", ">= 2.14.1"
|
9
10
|
s.add_development_dependency "timecop", "~> 0.7", ">= 0.7.1"
|
10
11
|
s.summary = "Elasticsearch query language"
|
data/spec/limit_spec.rb
ADDED
data/spec/regexp_spec.rb
CHANGED
@@ -5,7 +5,10 @@ describe 'regexp searches' do
|
|
5
5
|
it 'should parse foo=/blah foo/' do
|
6
6
|
result = Plunk.search 'foo=/blah foo/'
|
7
7
|
expected = Plunk::Helper.filter_builder(
|
8
|
-
Plunk::Helper.
|
8
|
+
Plunk::Helper.regexp_builder(
|
9
|
+
'foo',
|
10
|
+
'blah foo'
|
11
|
+
)
|
9
12
|
)
|
10
13
|
expect(result).to eq(expected)
|
11
14
|
end
|
@@ -13,7 +16,10 @@ describe 'regexp searches' do
|
|
13
16
|
it 'should parse foo=/blah\/ foo/' do
|
14
17
|
result = Plunk.search 'foo=/blah\/ foo/'
|
15
18
|
expected = Plunk::Helper.filter_builder(
|
16
|
-
Plunk::Helper.
|
19
|
+
Plunk::Helper.regexp_builder(
|
20
|
+
'foo',
|
21
|
+
'blah\/ foo'
|
22
|
+
)
|
17
23
|
)
|
18
24
|
expect(result).to eq(expected)
|
19
25
|
end
|
@@ -21,15 +27,21 @@ describe 'regexp searches' do
|
|
21
27
|
it 'should parse foo=/blah\. foo/' do
|
22
28
|
result = Plunk.search 'foo=/blah\. foo/'
|
23
29
|
expected = Plunk::Helper.filter_builder(
|
24
|
-
Plunk::Helper.
|
30
|
+
Plunk::Helper.regexp_builder(
|
31
|
+
'foo',
|
32
|
+
'blah\. foo'
|
33
|
+
)
|
25
34
|
)
|
26
35
|
expect(result).to eq(expected)
|
27
36
|
end
|
28
37
|
|
29
|
-
it 'should parse
|
30
|
-
result = Plunk.search '
|
38
|
+
it 'should parse http.headers=/.*User\-Agent\: Microsoft\-WebDAV.*/' do
|
39
|
+
result = Plunk.search 'http.headers=/.*User\-Agent\: Microsoft\-WebDAV.*/'
|
31
40
|
expected = Plunk::Helper.filter_builder(
|
32
|
-
Plunk::Helper.
|
41
|
+
Plunk::Helper.regexp_builder(
|
42
|
+
'http.headers',
|
43
|
+
'.*User\-Agent\: Microsoft\-WebDAV.*'
|
44
|
+
)
|
33
45
|
)
|
34
46
|
expect(result).to eq(expected)
|
35
47
|
end
|
data/spec/window_spec.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/time_stubs'
|
3
|
+
require 'shared/plunk_stubs'
|
4
|
+
require 'chronic'
|
5
|
+
|
6
|
+
describe 'the window command' do
|
7
|
+
include_context 'time stubs'
|
8
|
+
include_context 'plunk stubs'
|
9
|
+
|
10
|
+
it 'should parse window 3/11/13 to 3/12/13' do
|
11
|
+
result = Plunk.search 'window 3/11/13 to 3/12/13'
|
12
|
+
expected = Plunk::Helper.filter_builder(
|
13
|
+
Plunk::Helper.range_builder(
|
14
|
+
Plunk::Helper.timestamp_format(Chronic.parse('3/11/13')),
|
15
|
+
Plunk::Helper.timestamp_format(Chronic.parse('3/12/13'))
|
16
|
+
)
|
17
|
+
)
|
18
|
+
expect(result).to eq(expected)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should parse window "last monday" to "last thursday"' do
|
22
|
+
result = Plunk.search 'window "last monday" to "last thursday"'
|
23
|
+
expected = Plunk::Helper.filter_builder(
|
24
|
+
Plunk::Helper.range_builder(
|
25
|
+
Plunk::Helper.timestamp_format(Chronic.parse('last monday')),
|
26
|
+
Plunk::Helper.timestamp_format(Chronic.parse('last thursday'))
|
27
|
+
)
|
28
|
+
)
|
29
|
+
expect(result).to eq(expected)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should parse window -60m to -30m' do
|
33
|
+
result = Plunk.search 'window -60m to -30m'
|
34
|
+
expected = Plunk::Helper.filter_builder(
|
35
|
+
Plunk::Helper.range_builder(
|
36
|
+
Plunk::Helper.timestamp_format(@time - 60.minutes),
|
37
|
+
Plunk::Helper.timestamp_format(@time - 30.minutes)
|
38
|
+
)
|
39
|
+
)
|
40
|
+
expect(result).to eq(expected)
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plunk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ram Mehta
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-03-
|
13
|
+
date: 2014-03-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
@@ -92,6 +92,26 @@ dependencies:
|
|
92
92
|
- - '>='
|
93
93
|
- !ruby/object:Gem::Version
|
94
94
|
version: 4.0.0
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: chronic
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.10'
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 0.10.0
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ~>
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0.10'
|
112
|
+
- - '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: 0.10.0
|
95
115
|
- !ruby/object:Gem::Dependency
|
96
116
|
name: rspec
|
97
117
|
requirement: !ruby/object:Gem::Requirement
|
@@ -161,12 +181,14 @@ files:
|
|
161
181
|
- spec/chained_search_spec.rb
|
162
182
|
- spec/field_value_spec.rb
|
163
183
|
- spec/last_spec.rb
|
184
|
+
- spec/limit_spec.rb
|
164
185
|
- spec/nested_search_spec.rb
|
165
186
|
- spec/regexp_spec.rb
|
166
187
|
- spec/shared/dummy_client.rb
|
167
188
|
- spec/shared/plunk_stubs.rb
|
168
189
|
- spec/shared/time_stubs.rb
|
169
190
|
- spec/spec_helper.rb
|
191
|
+
- spec/window_spec.rb
|
170
192
|
homepage: https://github.com/elbii/plunk
|
171
193
|
licenses:
|
172
194
|
- MIT
|