whispr 0.0.3 → 0.1.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.
@@ -1,5 +1,10 @@
1
+ 0.1.0
2
+ - [2](https://github.com/simulacre/whispr/pull/2): allows closing the filehandle [ovesh](https://github.com/ovesh)
3
+ - IOError caught when reading header will be tagged as Whispr::Error rather than raising Whispr::CorruptWhisprFile
4
+ - support testing Whispr from specs using StringIO objects
5
+
1
6
  0.0.3
2
- - fixes: branch test and call to #update_one from #udpate_many
7
+ - fixes: branch test and call to #update_one from #update
3
8
  - [1](https://github.com/simulacre/whispr/pull/1): allows passing array to #update [ovesh](https://github.com/ovesh)
4
9
 
5
10
  0.0.2
@@ -75,57 +75,86 @@ class Whispr
75
75
  [precision, points]
76
76
  end
77
77
 
78
- # Create whipser file.
78
+ # Create whipser file on the file system and prepopulate it.
79
79
  # @param [String] path
80
80
  # @param [Array] archiveList each archive is an array with two elements: [secondsPerPoint,numberOfPoints]
81
81
  # @param [Hash] opts
82
- # @option opts [Float] :xff the fraction of data points in a propagation interval that must have known values for a propagation to occur
83
- # @option opts [Symbol] :aggregationMethod the function to use when propogating data; must be one of AGGR_TYPES[1..-1]
82
+ # @option opts [Float] :xff (0.5) the fraction of data points in a propagation interval that must have known values for a propagation to occur
83
+ # @option opts [Symbol] :aggregationMethod (average) the function to use when propogating data; must be one of AGGR_TYPES[1..-1]
84
84
  # @option opts [Boolean] :overwrite (false)
85
+ # @option opts [Boolean] :sparse (false)
85
86
  # @raise [InvalidConfiguration] if the archiveList is inavlid, or if 'path' exists and :overwrite is not true
86
87
  # @see Whsipr.validateArchiveList
87
88
  def create(path, archiveList, opts = {})
88
- opts = {:xff => 0.5, :aggregationMethod => :average, :sparse => false, :overwrite => false}.merge(opts)
89
- unless AGGR_TYPES[1..-1].include?(opts[:aggregationMethod])
90
- raise InvalidConfiguration.new("aggregationMethod must be one of #{AGGR_TYPES[1..-1]}")
91
- end
92
-
89
+ validate_opts(opts)
93
90
  validateArchiveList!(archiveList)
94
91
  raise InvalidConfiguration.new("File #{path} already exists!") if File.exists?(path) && !opts[:overwrite]
95
92
 
96
93
  # if file exists it will be truncated
97
94
  File.open(path, "wb") do |fh|
98
95
  fh.flock(File::LOCK_EX)
99
- aggregationType = AGGR_TYPES.index(opts[:aggregationMethod])
100
- oldest = archiveList.map{|spp, points| spp * points }.sort.last
101
- packedMetadata = [aggregationType, oldest, opts[:xff], archiveList.length].pack(METADATA_FMT)
102
- fh.write(packedMetadata)
103
- headerSize = METADATA_SIZE + (ARCHIVE_INFO_SIZE * archiveList.length)
104
- archiveOffsetPointer = headerSize
105
- archiveList.each do |spp, points|
106
- archiveInfo = [archiveOffsetPointer, spp, points].pack(ARCHIVE_INFO_FMT)
107
- fh.write(archiveInfo)
108
- archiveOffsetPointer += (points * POINT_SIZE)
109
- end
96
+ prepopulate(fh, archiveList, opts)
97
+ end
110
98
 
111
- if opts[:sparse]
112
- fh.seek(archiveOffsetPointer - headerSize - 1)
113
- fh.write("\0")
114
- else
115
- remaining = archiveOffsetPointer - headerSize
116
- zeroes = "\x00" * CHUNK_SIZE
117
- while remaining > CHUNK_SIZE
118
- fh.write(zeroes)
119
- remaining -= CHUNK_SIZE
120
- end
121
- fh.write(zeroes[0..remaining])
122
- end
99
+ new(path)
100
+ end
123
101
 
124
- fh.flush
125
- fh.fsync rescue nil
102
+ # Set defaults for the options to #create and #prepopulate as well as validate the supplied options.
103
+ # @param [Hash] opts
104
+ # @return [Hash] updated options
105
+ def validate_opts(opts = {})
106
+ opts = {:xff => 0.5, :aggregationMethod => :average, :sparse => false, :overwrite => false}.merge(opts)
107
+ unless AGGR_TYPES[1..-1].include?(opts[:aggregationMethod])
108
+ raise InvalidConfiguration.new("aggregationMethod must be one of #{AGGR_TYPES[1..-1]}")
126
109
  end
110
+ opts
111
+ end
127
112
 
128
- new(path)
113
+ # Build the header and reserve space for the archives in the Whispr file.
114
+ #
115
+ # You probably don't want to use this method, you probably want to use
116
+ # #create instead. Calls to prepopulate MUST be preceeded by a call to
117
+ # validateArchiveList! with the archiveList argument.
118
+ #
119
+ # @param [File] the filehandle that will hold the archive
120
+ # @param [Array] archiveList each archive is an array with two elements: [secondsPerPoint,numberOfPoints]
121
+ # @param [Hash] opts
122
+ # @option opts [Float] :xff the fraction of data points in a propagation interval that must have known values for a propagation to occur
123
+ # @option opts [Symbol] :aggregationMethod the function to use when propogating data; must be one of AGGR_TYPES[1..-1]
124
+ # @option opts [Boolean] :overwrite (false)
125
+ # @raise [InvalidConfiguration] if the archiveList is inavlid, or if 'path' exists and :overwrite is not true
126
+ # @see Whsipr.validateArchiveList
127
+ # @see Whsipr.create
128
+ def prepopulate(fh, archiveList, opts = {})
129
+ opts = validate_opts(opts)
130
+ aggregationType = AGGR_TYPES.index(opts[:aggregationMethod])
131
+ oldest = archiveList.map{|spp, points| spp * points }.sort.last
132
+ packedMetadata = [aggregationType, oldest, opts[:xff], archiveList.length].pack(METADATA_FMT)
133
+ fh.write(packedMetadata)
134
+ headerSize = METADATA_SIZE + (ARCHIVE_INFO_SIZE * archiveList.length)
135
+ archiveOffsetPointer = headerSize
136
+ archiveList.each do |spp, points|
137
+ archiveInfo = [archiveOffsetPointer, spp, points].pack(ARCHIVE_INFO_FMT)
138
+ fh.write(archiveInfo)
139
+ archiveOffsetPointer += (points * POINT_SIZE)
140
+ end
141
+
142
+ if opts[:sparse]
143
+ fh.seek(archiveOffsetPointer - headerSize - 1)
144
+ fh.write("\0")
145
+ else
146
+ remaining = archiveOffsetPointer - headerSize
147
+ zeroes = "\x00" * CHUNK_SIZE
148
+ while remaining > CHUNK_SIZE
149
+ fh.write(zeroes)
150
+ remaining -= CHUNK_SIZE
151
+ end
152
+ fh.write(zeroes[0..remaining])
153
+ end
154
+
155
+ fh.flush
156
+ fh.fsync rescue nil
157
+ fh
129
158
  end
130
159
 
131
160
  # Is the provided archive list valid?
@@ -253,6 +282,14 @@ class Whispr
253
282
  end
254
283
  end
255
284
 
285
+ def closed?
286
+ @fh.closed?
287
+ end
288
+
289
+ def close
290
+ @fh.close
291
+ end
292
+
256
293
  private
257
294
 
258
295
 
@@ -273,6 +310,8 @@ private
273
310
  :offset => offset
274
311
  }
275
312
  end
313
+ rescue IOError => e
314
+ raise e.extend(Error)
276
315
  rescue => e
277
316
  raise CorruptWhisprFile.exception(e)
278
317
  ensure
@@ -1,3 +1,3 @@
1
1
  class Whispr
2
- VERSION = '0.0.3'
2
+ VERSION = '0.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whispr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-09 00:00:00.000000000 Z
12
+ date: 2014-01-31 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ''
15
15
  email: whispr@simulacre.org