influxparser 0.0.2 → 0.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 599f27d2ff8251400b2b593b79e0ca7facad4aff
4
- data.tar.gz: 84c2792855209669e2bc8e4a41aec43c393be2e1
3
+ metadata.gz: 8a35192cf489f487d8a42343384e1528d5168047
4
+ data.tar.gz: fa965f4209d17c97bf4bde7508c5cc9fe07cfcd0
5
5
  SHA512:
6
- metadata.gz: a5a8a3e29905ac2f31915e7be9dc2e7dcb987f5375a0a80f871720b8e859386397d70c1e73a2b58982db45946a04d0146a82660d6c95dd3f646a2460c3be4335
7
- data.tar.gz: 1f97c90e05e42b503ef03283f72cb22ba176f00564c18e356cd998a5dd587f78f2990aa732da1e1e985c8f3f054263149d306efaa15851641c8862c93952d365
6
+ metadata.gz: 870efd15c7c9df408b15a2da2dc11134c6c2bd45ff69bdd213b30a3913fb402b0d992626c42bfee7a944dbbfe4624a922baffe6e0c6d5c2cb995170c9a6c74d5
7
+ data.tar.gz: 194488b6bcb2ed5ce444c603789c6db5ce8b321f2ed15b70567f19b35afd7a0fb5e15cc78be828bf99d30809f0f23ea845a10d5b9da5d0949fe53db4ac43eae6
@@ -1,13 +1,13 @@
1
1
  # TODO: the tags hash should be absent when there are no tags
2
- # TODO: numbers shouldn't be strings
3
- # TODO: numbers which aren't strings are floats
4
- # TODO: numbers with a trailing i are integers -- ALERT this is actually broken
5
2
  # TODO: optional timestamp parsing
6
3
  # TODO: time key shouldn't exist if there is no time
7
4
  # TODO: deal with improper line protocol
8
5
  class InfluxParser
9
6
  class << self
10
- def parse_point(s)
7
+ def parse_point(s, options = {})
8
+ default_options = {:parse_types => true}
9
+ options = default_options.merge(options)
10
+
11
11
  point = {}
12
12
  point['_raw'] = s
13
13
  s = s.strip # trim whitespace
@@ -26,29 +26,30 @@ class InfluxParser
26
26
  end
27
27
 
28
28
  # now iterate over the values
29
- last_value = ''
29
+ last_value_raw = ''
30
30
  last_key = ''
31
31
  point['values'] = {}
32
32
  vparts = s[measurement_end+1..-1].split(/(?<!\\),/)
33
+ # puts "vparts:#{vparts}"
33
34
  vparts.each do |v|
34
35
  value = v.split(/(?<!\\)=/)
35
- last_value = unescape_point value[1]
36
+ last_value_raw = value[1]
36
37
  last_key = unescape_tag value[0]
37
- # puts "kv:#{last_key}==#{last_value}"
38
- point['values'][last_key] = last_value
38
+ # puts "last k/v #{last_key}==#{last_value_raw}"
39
+ point['values'][last_key] = unescape_point(value[1],options)
39
40
  end
40
-
41
+ # puts "-----\n#{point['values'].to_yaml}\n"
41
42
  # check for a timestamp in the last value
42
43
  # TODO: I hate this, but it's late and I just want to move past it for now
43
44
  # TODO: what happens if the last character of the last value is an escaped quote?
44
- has_space = last_value.rindex(/ /)
45
+ has_space = last_value_raw.rindex(/ /)
45
46
  if has_space
46
- time_stamp = last_value[has_space+1..-1] # take everything from the space to the end
47
+ time_stamp = last_value_raw[has_space+1..-1] # take everything from the space to the end
47
48
  if time_stamp.index(/"/)
48
49
  point['time'] = nil
49
50
  else
50
51
  # it was a timestamp, strip it from the last value and set the timestamp
51
- point['values'][last_key] = unescape_point last_value[0..has_space-1]
52
+ point['values'][last_key] = unescape_point(last_value_raw[0..has_space-1],options)
52
53
  point['time'] = time_stamp
53
54
  end
54
55
  else
@@ -64,16 +65,24 @@ class InfluxParser
64
65
  t = unescape_measurement s
65
66
  t.gsub(/\\=/,'=')
66
67
  end
67
- def unescape_point(s)
68
- if s[-1,1] == '"'
68
+ def unescape_point(s,options)
69
+ # puts "unescape:#{s}"
70
+ # s = s.gsub(/\\\\/,'\\').gsub(/\\"/,'""') # handle escaped characters if present
69
71
 
70
- # it's a quoted string and should be unescaped
71
- s = s[1..-2] # take the wrapping quotes off
72
- return s.gsub(/\\\\/,'\\').gsub(/\\"/,',')
73
- else
74
- # it's a number and if it's trailing an i we need to strip it because we're not handling precision here
75
- return s.chomp('i')
76
- end
72
+ # it is a string, return it
73
+ return s[1..-2].gsub(/\\\\/,'\\').gsub(/\\"/,'""') if s[0,1] == '"'
74
+
75
+ return s.sub(/(?<=\d)i/,'') if (!options[:parse_types]) # the customer doesn't care about types so just return it, but strip the trailing i from an integer because we care
76
+
77
+ # handle the booleans
78
+ return true if ['t','T','true','True','TRUE'].include?(s)
79
+ return false if ['f','F','false','False','FALSE'].include?(s)
80
+
81
+ # by here we have either an unquoted string or some numeric
82
+
83
+ return s.to_f if s =~ /^(\d|\.)+$/ # floats are only digits and dots
84
+ return s.chomp('i').to_i if s[0..-2] =~ /^(\d)+$/ # trailing i is an integer remove it
85
+ return s.gsub(/\\\\/,'\\').gsub(/\\"/,'"')
77
86
  end
78
87
  end
79
88
  end
@@ -30,7 +30,7 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
30
30
 
31
31
  # value
32
32
  assert_equal(true,point['values'].key?('temperature'))
33
- assert_equal('82',point['values']['temperature'])
33
+ assert_equal(82,point['values']['temperature'])
34
34
 
35
35
  # time
36
36
  assert_equal('1465839830100400200',point['time'])
@@ -50,7 +50,7 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
50
50
 
51
51
  # value
52
52
  assert_equal(true,point['values'].key?('temperature'))
53
- assert_equal('82',point['values']['temperature'])
53
+ assert_equal(82,point['values']['temperature'])
54
54
 
55
55
  # time
56
56
  assert_equal('1465839830100400200',point['time'])
@@ -72,10 +72,10 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
72
72
  assert_equal(2,point['values'].length)
73
73
 
74
74
  assert_equal(true,point['values'].key?('temperature'))
75
- assert_equal('82',point['values']['temperature'])
75
+ assert_equal(82,point['values']['temperature'])
76
76
 
77
77
  assert_equal(true,point['values'].key?('humidity'))
78
- assert_equal('71',point['values']['humidity'])
78
+ assert_equal(71,point['values']['humidity'])
79
79
 
80
80
  # time
81
81
  assert_equal('1465839830100400200',point['time'])
@@ -90,12 +90,12 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
90
90
  def test_float
91
91
  point = InfluxParser.parse_point('weather,location=us-midwest temperature=82 1465839830100400200')
92
92
  assert_not_equal(false,point) # a straight up parse error will false
93
- assert_equal('82',point['values']['temperature'])
93
+ assert_equal(82.0,point['values']['temperature'])
94
94
  end
95
95
  def test_integer
96
96
  point = InfluxParser.parse_point('weather,location=us-midwest temperature=82i 1465839830100400200')
97
97
  assert_not_equal(false,point) # a straight up parse error will false
98
- assert_equal('82',point['values']['temperature'])
98
+ assert_equal(82,point['values']['temperature'])
99
99
  end
100
100
 
101
101
  def test_string
@@ -118,36 +118,45 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
118
118
  end
119
119
 
120
120
  def test_boolean
121
- # TODO: validate the parsed booleans are bools and expected
122
121
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=t 1465839830100400200")
123
122
  assert_not_equal(false,point) # a straight up parse error will false
123
+ assert_equal(true,point['values']['temperature'])
124
124
 
125
125
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=T 1465839830100400200")
126
126
  assert_not_equal(false,point) # a straight up parse error will false
127
+ assert_equal(true,point['values']['temperature'])
127
128
 
128
129
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=true 1465839830100400200")
129
130
  assert_not_equal(false,point) # a straight up parse error will false
131
+ assert_equal(true,point['values']['temperature'])
130
132
 
131
133
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=True 1465839830100400200")
132
134
  assert_not_equal(false,point) # a straight up parse error will false
135
+ assert_equal(true,point['values']['temperature'])
133
136
 
134
137
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=TRUE 1465839830100400200")
135
138
  assert_not_equal(false,point) # a straight up parse error will false
139
+ assert_equal(true,point['values']['temperature'])
136
140
 
137
141
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=f 1465839830100400200")
138
142
  assert_not_equal(false,point) # a straight up parse error will false
143
+ assert_equal(false,point['values']['temperature'])
139
144
 
140
145
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=F 1465839830100400200")
141
146
  assert_not_equal(false,point) # a straight up parse error will false
147
+ assert_equal(false,point['values']['temperature'])
142
148
 
143
149
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=false 1465839830100400200")
144
150
  assert_not_equal(false,point) # a straight up parse error will false
151
+ assert_equal(false,point['values']['temperature'])
145
152
 
146
153
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=False 1465839830100400200")
147
154
  assert_not_equal(false,point) # a straight up parse error will false
155
+ assert_equal(false,point['values']['temperature'])
148
156
 
149
157
  point = InfluxParser.parse_point("weather,location=us-midwest temperature=FALSE 1465839830100400200")
150
158
  assert_not_equal(false,point) # a straight up parse error will false
159
+ assert_equal(false,point['values']['temperature'])
151
160
 
152
161
  end
153
162
  def test_ridiculous_quotes
@@ -165,7 +174,7 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
165
174
  # check values
166
175
 
167
176
  assert_equal(true,point['values'].key?('"temperature"'))
168
- assert_equal('82',point['values']['"temperature"'])
177
+ assert_equal(82,point['values']['"temperature"'])
169
178
 
170
179
  # time
171
180
  assert_equal('1465839830100400200',point['time'])
@@ -186,7 +195,7 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
186
195
  # check values
187
196
 
188
197
  assert_equal(true,point['values'].key?("'temperature'"))
189
- assert_equal('82',point['values']["'temperature'"])
198
+ assert_equal(82,point['values']["'temperature'"])
190
199
 
191
200
  # time
192
201
  assert_equal('1465839830100400200',point['time'])
@@ -200,7 +209,7 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
200
209
 
201
210
  point = InfluxParser.parse_point('weather,location=us-midwest temp\=rature=82 1465839830100400200')
202
211
  assert_not_equal(false,point) # a straight up parse error will false
203
- assert_equal('82',point['values']['temp=rature'])
212
+ assert_equal(82,point['values']['temp=rature'])
204
213
 
205
214
  point = InfluxParser.parse_point('weather,location\ place=us-midwest temperature=82 1465839830100400200')
206
215
  assert_not_equal(false,point) # a straight up parse error will false
@@ -214,6 +223,11 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
214
223
  assert_not_equal(false,point) # a straight up parse error will false
215
224
  assert_equal('wea ther',point['measurement'])
216
225
 
226
+ point = InfluxParser.parse_point('weather temperature=toohot\"')
227
+ assert_not_equal(false,point) # a straight up parse error will false
228
+ assert_equal('toohot"',point['values']['temperature'])
229
+
230
+
217
231
  # so many slashes -- note they're extra terrible because I need to escape ruby slashes in the test strings
218
232
 
219
233
  # forward slash
@@ -247,4 +261,21 @@ class TestParsePointFromDocs < Test::Unit::TestCase # def setup
247
261
  assert_equal("too hot\\\\\\cold",point['values']['temperature_str'])
248
262
 
249
263
  end
264
+ def test_types
265
+ point = InfluxParser.parse_point('weather float=82,integer=82i,impliedstring=helloworld,explicitstring="hello world" 1465839830100400200')
266
+ assert_not_equal(false,point) # a straight up parse error will false
267
+ assert_equal(82.0,point['values']['float'])
268
+ assert_equal(82,point['values']['integer'])
269
+ assert_equal('helloworld',point['values']['impliedstring'])
270
+ assert_equal('hello world',point['values']['explicitstring'])
271
+
272
+ # do it again but this time without type parsing
273
+ point = InfluxParser.parse_point('weather float=82,integer=82i,impliedstring=helloworld,explicitstring="hello world" 1465839830100400200',{:parse_types => false})
274
+ assert_not_equal(false,point) # a straight up parse error will false
275
+ assert_equal('82',point['values']['float'])
276
+ assert_equal('82',point['values']['integer'])
277
+ assert_equal('helloworld',point['values']['impliedstring'])
278
+ assert_equal('hello world',point['values']['explicitstring'])
279
+
280
+ end
250
281
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: influxparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Labrie