dumb_delimited 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a4d7deecbbed56e6940058fdc548436cbdb0f081b43164bc841017601c27726
4
- data.tar.gz: b94ae4701ae2dec7cee54befe2e85c11ea20a9ae5906d0f7da6a8da1ef377eb6
3
+ metadata.gz: '049c4e61de54be67ca44c3b01d7f97fd5f1972953415ed339a14c55ec0c6d0c4'
4
+ data.tar.gz: 38f8e15d6a44ab8af339cf4da8e8addb232c8118ba1b8603e31deb934ca95989
5
5
  SHA512:
6
- metadata.gz: 9f2994715b89523b10c4fb1375b2a073e306cedfae565f502241a4ad8f82876b1ec02d1b453641842ca331bba2812ea73783c70af7cc1431b0bbaeec83e0ce09
7
- data.tar.gz: 36b9db417ddd340f695e1332ea005ad8ec03c3e8d31f5cc395b8479463497bee0e518e89f5916a90d0267ebfe9779abb21995d35e66f8da67b91f282e955b2b1
6
+ metadata.gz: 47aea2da44d901f3606f9e997f6024dd0413f131bec2f7f53db73863c7975a4102996f45a6eef2ffecdbf97d12c2b27132b9689dbb51f1911b1fa4f3419d9c4f
7
+ data.tar.gz: a4e067dccc15b8588ab721da6e12e5175be63febce3b25198178324944e60b248a1e9927c23b738beba4df6752525c451a8eeaf65553bacf79a017a069a4dbb4
@@ -1,8 +1,29 @@
1
+ ## 2.0.0
2
+
3
+ * [BREAKING] Do not activate `options[:converters]` by default
4
+ * [BREAKING] Remove *pleasant_path* dependency. This is considered a
5
+ breaking change because *pleasant_path* adds extension methods to
6
+ several Ruby core classes that consumer code may depend on.
7
+ * [BREAKING] Remove `append_to_file` instance method
8
+ * [BREAKING] Rename `each_in_file` class method to `read_each`
9
+ * Add `parse_each` class method
10
+ * Rename `parse_file` class method to `read`, and alias as `parse_file`
11
+ * Rename `parse_text` class method to `parse`, and alias as `parse_text`
12
+ * Add `write` class method
13
+ * Add `append` class method
14
+ * Add `eol` parameter to `to_s` instance method
15
+ * Add `DumbDelimited.csv`, `.psv`, and `.tsv` convenience shortcuts
16
+ * Activate `options[:liberal_parsing]` by default
17
+ * Make `options` inheritable
18
+ * Fix behavior when `options[:headers]` is set
19
+ * Fix behavior when `options[:write_headers]` is set
20
+
21
+
1
22
  ## 1.1.0
2
23
 
3
- * Fixed gem load on case-sensitive file systems.
4
- * Added `parse_text` class method.
5
- * Added `append_to_file` instance method.
24
+ * Add `parse_text` class method
25
+ * Add `append_to_file` instance method
26
+ * Fix gem load on case-sensitive file systems
6
27
 
7
28
 
8
29
  ## 1.0.0
data/README.md CHANGED
@@ -33,7 +33,7 @@ used as a superclass or simply assigned to a constant.
33
33
  ```ruby
34
34
  class Product < DumbDelimited[:sku, :name, :base_price, :sale_price]
35
35
  def on_sale?
36
- sale_price < base_price
36
+ sale_price.to_f < base_price.to_f
37
37
  end
38
38
  end
39
39
 
@@ -42,57 +42,71 @@ Customer.delimiter = "|"
42
42
  ```
43
43
 
44
44
  Because "customers.psv" is pipe-delimited, we also set the delimiter
45
- for the Customer class. By default, model classes use comma (`","`) as
46
- the delimiter. Whenever a delimiter is set, it applies to all future
45
+ for the Customer class. By default, a model class uses a comma (`","`)
46
+ as its delimiter. Whenever a delimiter is set, it applies to all future
47
47
  IO operations for that model class.
48
48
 
49
- Now we can read each flat file, and recieve an array of model objects.
49
+ Convenience shortcuts that create a model class and set its delimiter
50
+ are also provided for a few common delimiters. Notably,
51
+ `DumbDelimited::psv` for a model class with a pipe (`"|"`) delimiter.
52
+ Thus, the `Customer` class could alternatively be written as:
50
53
 
51
54
  ```ruby
52
- products = Product.parse_file("products.csv")
53
- customers = Customer.parse_file("customers.psv")
55
+ Customer = DumbDelimited.psv(:name, :email, :address)
54
56
  ```
55
57
 
56
- This, however, will load the entire contents of each file into memory.
58
+ Using our model classes, we can read each flat file, and recieve an
59
+ array of model objects:
60
+
61
+ ```ruby
62
+ products = Product.read("products.csv")
63
+ customers = Customer.read("customers.psv")
64
+ ```
65
+
66
+ However, this will load the entire contents of each file into memory.
57
67
  Let's say our customers file is very large, and we would prefer to
58
- iterate over it rather than load it all into memory at once. To do so,
59
- we can use the `each_in_file` method that the model class provides.
60
- Below is a complete example in which we load our product data, create a
61
- listing of products on sale, and iterate over our customers, notifying
62
- each customer of the sale products:
68
+ iterate over it one row at a time rather than load it all into memory at
69
+ once. To do so, we can use the `read_each` method. Below is a complete
70
+ example in which we load our product data, create a listing of products
71
+ on sale, and iterate over our customers, notifying each customer of the
72
+ sale products:
63
73
 
64
74
  ```ruby
65
- products = Product.parse_file("products.csv")
75
+ products = Product.read("products.csv")
66
76
 
67
77
  listing = products.select(&:on_sale?).map do |product|
68
78
  "* #{product.name} (#{product.sale_price})"
69
79
  end.join("\n")
70
80
 
71
- Customer.each_in_file("customers.psv") do |customer|
72
- message =
73
- "Hi #{customer.name}!\n\n" \
74
- "The following products are on sale:\n\n#{listing}"
81
+ Customer.read_each("customers.psv") do |customer|
82
+ message = <<~MESSAGE
83
+ Hi #{customer.name}!
84
+
85
+ The following products are on sale:
86
+
87
+ #{listing}
88
+ MESSAGE
75
89
 
76
90
  notify(customer.email, message)
77
91
  end
78
92
  ```
79
93
 
80
94
  Let's say the sale is now over, and we want to change our sale prices
81
- back to our base prices. *dumb_delimited* includes the
82
- [*pleasant_path*](https://rubygems.org/gems/pleasant_path) gem, which
83
- offers a fluent API for writing files. To finish our task, we use the
84
- `Array#write_to_file` method provided by *pleasant_path*, which in turn
85
- invokes `Product#to_s` (provided by *dumb_delimited*) on each model
86
- object.
95
+ back to our base prices. We can load our product data, modify it
96
+ directly, and finally persist it back with the `write` method:
87
97
 
88
98
  ```ruby
89
- Product.parse_file("products.csv").each do |product|
99
+ products = Product.read("products.csv")
100
+
101
+ products.each do |product|
90
102
  product.sale_price = product.base_price
91
- end.write_to_file("products.csv")
103
+ end
104
+
105
+ Product.write("products.csv", products)
92
106
  ```
93
107
 
94
108
  For a more detailed explanation of the *dumb_delimited* API, browse the
95
- [full documentation](http://www.rubydoc.info/gems/dumb_delimited/).
109
+ [API documentation](http://www.rubydoc.info/gems/dumb_delimited/).
96
110
 
97
111
 
98
112
  ## Installation
@@ -20,8 +20,6 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_runtime_dependency "pleasant_path", "~> 1.0"
24
-
25
23
  spec.add_development_dependency "bundler", "~> 1.15"
26
24
  spec.add_development_dependency "rake", "~> 10.0"
27
25
  spec.add_development_dependency "minitest", "~> 5.0"
@@ -1,28 +1,29 @@
1
1
  require "csv"
2
- require "pleasant_path"
3
2
  require_relative "dumb_delimited/version"
4
3
 
5
4
 
6
5
  module DumbDelimited
7
6
 
8
7
  # Returns a model class for delimited data consisting of the specified
9
- # columns. The returned class inherits from Ruby's
10
- # {https://ruby-doc.org/core/Struct.html +Struct+}, allowing data
11
- # manipulation via accessor methods, via indexing by column name, and
12
- # via indexing by column number. See {ClassMethods} and
13
- # {InstanceMethods} for the IO methods the returned class provides.
8
+ # +columns+. The returned class inherits from Ruby's
9
+ # {https://docs.ruby-lang.org/en/trunk/Struct.html +Struct+}, allowing
10
+ # data manipulation via accessor methods, via indexing by column name,
11
+ # and via indexing by column number. See {ClassMethods} and
12
+ # {InstanceMethods} for the additional methods the returned class
13
+ # provides.
14
14
  #
15
15
  # @example
16
16
  # class Product < DumbDelimited[:sku, :name, :base_price, :sale_price]
17
17
  # def on_sale?
18
- # sale_price < base_price
18
+ # sale_price.to_f < base_price.to_f
19
19
  # end
20
20
  # end
21
21
  #
22
+ # @example
22
23
  # Customer = DumbDelimited[:name, :email, :address]
23
24
  #
24
- # @param columns [*Symbol]
25
- # @return [Class]
25
+ # @param columns [Array<Symbol>]
26
+ # @return [Class<Struct>]
26
27
  def self.[](*columns)
27
28
  Struct.new(*columns) do
28
29
  extend DumbDelimited::ClassMethods
@@ -30,42 +31,111 @@ module DumbDelimited
30
31
  end
31
32
  end
32
33
 
34
+ # Convenience shortcut to create a model class and set
35
+ # {ClassMethods#delimiter} to +","+.
36
+ #
37
+ # Note: This method exists mostly for parity with {psv} and {tsv}.
38
+ # Unless +CSV::DEFAULT_OPTIONS+ has been modified, the delimiter will
39
+ # already default to +","+.
40
+ #
41
+ # @example
42
+ # # This...
43
+ # Point = DumbDelimited.csv(:x, :y, :z)
44
+ #
45
+ # # ...is equivalent to:
46
+ # Point = DumbDelimited[:x, :y, :z]
47
+ # Point.delimiter = ","
48
+ #
49
+ # @param columns [Array<Symbol>]
50
+ # @return [Class<Struct>]
51
+ def self.csv(*columns)
52
+ klass = self[*columns]
53
+ klass.delimiter = ","
54
+ klass
55
+ end
56
+
57
+ # Convenience shortcut to create a model class and set
58
+ # {ClassMethods#delimiter} to +"|"+.
59
+ #
60
+ # @example
61
+ # # This...
62
+ # Point = DumbDelimited.psv(:x, :y, :z)
63
+ #
64
+ # # ...is equivalent to:
65
+ # Point = DumbDelimited[:x, :y, :z]
66
+ # Point.delimiter = "|"
67
+ #
68
+ # @param columns [Array<Symbol>]
69
+ # @return [Class<Struct>]
70
+ def self.psv(*columns)
71
+ klass = self[*columns]
72
+ klass.delimiter = "|"
73
+ klass
74
+ end
75
+
76
+ # Convenience shortcut to create a model class and set
77
+ # {ClassMethods#delimiter} to <code>"\t"</code>.
78
+ #
79
+ # @example
80
+ # # This...
81
+ # Point = DumbDelimited.tsv(:x, :y, :z)
82
+ #
83
+ # # ...is equivalent to:
84
+ # Point = DumbDelimited[:x, :y, :z]
85
+ # Point.delimiter = "\t"
86
+ #
87
+ # @param columns [Array<Symbol>]
88
+ # @return [Class<Struct>]
89
+ def self.tsv(*columns)
90
+ klass = self[*columns]
91
+ klass.delimiter = "\t"
92
+ klass
93
+ end
94
+
33
95
  end
34
96
 
35
97
 
36
98
  module DumbDelimited::ClassMethods
37
99
 
38
- # Returns the advanced options Hash. The Hash is not +dup+ed and can
39
- # be modified directly. Any modifications will be applied to all
40
- # future IO operations for the model class. For detailed information
41
- # about available options, see Ruby's
42
- # {http://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html#method-c-new
43
- # CSV module}.
100
+ # Returns the CSV options Hash. The Hash is not +dup+ed and can be
101
+ # modified directly. Any modifications will be applied to all future
102
+ # IO operations for the model class.
44
103
  #
45
- # @return [Hash]
104
+ # For detailed information about available options, see Ruby's
105
+ # {https://docs.ruby-lang.org/en/trunk/CSV.html#method-c-new CSV
106
+ # class}.
107
+ #
108
+ # @return [Hash<Symbol, Object>]
46
109
  def options
47
- @options ||= {
48
- col_sep: ",",
49
- skip_blanks: true,
50
- converters: :numeric,
51
- }
110
+ @options ||= if superclass == Struct
111
+ CSV::DEFAULT_OPTIONS.merge(
112
+ skip_blanks: true,
113
+ liberal_parsing: true,
114
+ )
115
+ else
116
+ superclass.options.dup
117
+ end
52
118
  end
53
119
 
54
- # Sets the advanced options Hash. The entire Hash is replaced, and
55
- # the new value will be applied to all future IO operations for the
56
- # model class. To set options individually, see {options}. For
57
- # detailed information about available options, see Ruby's
58
- # {http://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html#method-c-new
59
- # CSV module}.
120
+ # Sets the CSV options Hash. The entire Hash is replaced, and the new
121
+ # values will be applied to all future IO operations for the model
122
+ # class. To set options individually, see {options}.
60
123
  #
61
- # @param o [Hash]
62
- def options=(o)
63
- @options = o
124
+ # For detailed information about available options, see Ruby's
125
+ # {https://docs.ruby-lang.org/en/trunk/CSV.html#method-c-new CSV
126
+ # class}.
127
+ #
128
+ # @param opts [Hash<Symbol, Object>]
129
+ # @return [Hash<Symbol, Object>]
130
+ def options=(opts)
131
+ @options = opts
64
132
  end
65
133
 
66
134
  # Returns the column delimiter used in IO operations. Defaults to a
67
135
  # comma (<code>","</code>).
68
136
  #
137
+ # Equivalent to <code>options[:col_sep]</code>.
138
+ #
69
139
  # @return [String]
70
140
  def delimiter
71
141
  self.options[:col_sep]
@@ -76,6 +146,8 @@ module DumbDelimited::ClassMethods
76
146
  # delimiter can be safely chosen, and all IO operations will quote
77
147
  # field values as necessary.
78
148
  #
149
+ # Equivalent to <code>options[:col_sep] = delim</code>.
150
+ #
79
151
  # @example
80
152
  # Point = DumbDelimited[:x, :y, :z]
81
153
  # p = Point.new(1, 2, 3)
@@ -83,9 +155,10 @@ module DumbDelimited::ClassMethods
83
155
  # Point.delimiter = "|"
84
156
  # p.to_s # == "1|2|3"
85
157
  #
86
- # @param d [String]
87
- def delimiter=(d)
88
- self.options[:col_sep] = d
158
+ # @param delim [String]
159
+ # @return [String]
160
+ def delimiter=(delim)
161
+ self.options[:col_sep] = delim
89
162
  end
90
163
 
91
164
  # Parses a single delimited line into a model object.
@@ -95,34 +168,53 @@ module DumbDelimited::ClassMethods
95
168
  # Point.parse_line("1,2,3") # == Point.new(1, 2, 3)
96
169
  #
97
170
  # @param line [String]
98
- # @return [self]
171
+ # @return [Struct]
99
172
  def parse_line(line)
100
- self.new(*CSV.parse_line(line, self.options))
173
+ parse_each(line).first
101
174
  end
102
175
 
103
- # Parses a string into an array of model objects.
176
+ # Parses a string or IO object into an array of model objects.
104
177
  #
105
178
  # @example
106
179
  # Point = DumbDelimited[:x, :y, :z]
107
- # Point.parse_text("1,2,3\n4,5,6\n7,8,9\n")
180
+ # Point.parse("1,2,3\n4,5,6\n7,8,9\n")
108
181
  # # == [
109
182
  # # Point.new(1, 2, 3),
110
183
  # # Point.new(4, 5, 6),
111
184
  # # Point.new(7, 8, 9)
112
185
  # # ]
113
186
  #
114
- # @param text [String]
115
- # @return [Array<self>]
116
- def parse_text(text)
117
- # using CSV.new.each instead of CSV.parse to avoid unnecessary mass
118
- # memory allocation and deallocation
119
- CSV.new(text, self.options).each.map{|row| self.new(*row) }
187
+ # @param data [String, IO]
188
+ # @return [Array<Struct>]
189
+ def parse(data)
190
+ parse_each(data).to_a
191
+ end
192
+
193
+ alias_method :parse_text, :parse
194
+
195
+ # Parses a string or IO object one line at a time, yielding a model
196
+ # object for each line.
197
+ #
198
+ # An Enumerator is returned if no block is given.
199
+ #
200
+ # @overload parse_each(data, &block)
201
+ # @param data [String, IO]
202
+ # @yieldparam model [Struct]
203
+ # @return [void]
204
+ #
205
+ # @overload parse_each(data)
206
+ # @param data [String, IO]
207
+ # @return [Enumerator<Struct>]
208
+ def parse_each(data, &block)
209
+ return to_enum(__method__, data) unless block_given?
210
+
211
+ csv_each(CSV.new(data, self.options), &block)
120
212
  end
121
213
 
122
- # Parses an entire delimited file into an array of model objects.
123
- # This will load the entire contents of the file into memory, and may
124
- # not be suitable for large files. To iterate over file contents
125
- # without loading it all into memory at once, use {each_in_file}.
214
+ # Parses a file into an array of model objects. This will load the
215
+ # entire contents of the file into memory, and may not be suitable for
216
+ # large files. To iterate over file contents without loading it all
217
+ # into memory at once, use {read_each}.
126
218
  #
127
219
  # @example
128
220
  # # CONTENTS OF FILE "points.csv":
@@ -131,7 +223,7 @@ module DumbDelimited::ClassMethods
131
223
  # # 7,8,9
132
224
  #
133
225
  # Point = DumbDelimited[:x, :y, :z]
134
- # Point.parse_file("points.csv")
226
+ # Point.read("points.csv")
135
227
  # # == [
136
228
  # # Point.new(1, 2, 3),
137
229
  # # Point.new(4, 5, 6),
@@ -139,27 +231,77 @@ module DumbDelimited::ClassMethods
139
231
  # # ]
140
232
  #
141
233
  # @param path [String, Pathname]
142
- # @return [Array<self>]
143
- def parse_file(path)
144
- each_in_file(path).to_a
234
+ # @return [Array<Struct>]
235
+ def read(path)
236
+ read_each(path).to_a
145
237
  end
146
238
 
147
- # Iterates over a delimited file, parsing one row at a time into model
148
- # objects. This avoids loading the entire contents of the file into
149
- # memory at once. If a block is given, it will be passed a model
150
- # object for each row in the file. Otherwise, if a block is not
151
- # given, an Enumerator will be returned. Note that some Enumerator
152
- # methods, such as +Enumerator#to_a+, will cause the entire contents
153
- # of the file to be loaded into memory regardless.
239
+ alias_method :parse_file, :read
240
+
241
+ # Parses a file one line at a time, yielding a model object for each
242
+ # line. This avoids loading the entire contents of the file into
243
+ # memory at once.
154
244
  #
155
- # @param path [String, Pathname]
156
- # @yieldparam [self] current model object
157
- # @return [Enumerator<self>, nil]
158
- def each_in_file(path)
245
+ # An Enumerator is returned if no block is given. Note that some
246
+ # Enumerator methods, such as +Enumerator#to_a+, can cause the entire
247
+ # contents of the file to be loaded into memory.
248
+ #
249
+ # @overload read_each(path, &block)
250
+ # @param path [String, Pathname]
251
+ # @yieldparam model [Struct]
252
+ # @return [void]
253
+ #
254
+ # @overload read_each(path)
255
+ # @param path [String, Pathname]
256
+ # @return [Enumerator<Struct>]
257
+ def read_each(path, &block)
159
258
  return to_enum(__method__, path) unless block_given?
160
259
 
161
- CSV.foreach(path, self.options) do |row|
162
- yield self.new(*row)
260
+ CSV.open(path, self.options) do |csv|
261
+ csv_each(csv, &block)
262
+ end
263
+ end
264
+
265
+ # Writes a collection of model objects to a file in delimited format.
266
+ # The previous contents of the file are overwritten, unless +append+
267
+ # is set to true.
268
+ #
269
+ # Column headers are written to the file if +:write_headers+ in
270
+ # {options} is set to true *and* either +append+ is false or the file
271
+ # is empty / non-existent. The column headers will be derived from
272
+ # either the value of +:headers+ in {options} if it is an Array, or
273
+ # otherwise from the columns defined by the model.
274
+ #
275
+ # @param path [String, Pathname]
276
+ # @param models [Enumerable<Struct>]
277
+ # @param append [Boolean]
278
+ # @return [void]
279
+ def write(path, models, append: false)
280
+ mode = append ? "a" : "w"
281
+ write_headers = options[:write_headers] && !(append && File.exist?(path) && File.size(path) > 0)
282
+ headers = (!options[:headers].is_a?(Array) && write_headers) ? members : options[:headers]
283
+
284
+ CSV.open(path, mode, **options, write_headers: write_headers, headers: headers) do |csv|
285
+ models.each{|model| csv << model }
286
+ end
287
+ end
288
+
289
+ # Appends a collection of model objects to a file in delimited format.
290
+ # Convenience shortcut for {write} with +append: true+.
291
+ #
292
+ # @param path [String, Pathname]
293
+ # @param models [Enumerable<Struct>]
294
+ # @return [void]
295
+ def append(path, models)
296
+ write(path, models, append: true)
297
+ end
298
+
299
+ private
300
+
301
+ def csv_each(csv, &block)
302
+ csv.each do |row|
303
+ row = row.fields if row.is_a?(CSV::Row)
304
+ block.call(self.new(*row))
163
305
  end
164
306
  end
165
307
 
@@ -169,33 +311,19 @@ end
169
311
  module DumbDelimited::InstanceMethods
170
312
 
171
313
  # Serializes a model object to a delimited string, using the delimiter
172
- # specified by {ClassMethods.delimiter}.
314
+ # specified by {ClassMethods#delimiter}. By default, the string will
315
+ # not end with a line terminator. To end the string with a line
316
+ # terminator designated by +:row_sep+ in {ClassMethods#options}, set
317
+ # +eol+ to true.
173
318
  #
319
+ # @param eol [Boolean]
174
320
  # @return [String]
175
- def to_s
176
- CSV.generate_line(self, self.class.options).chomp!
177
- end
321
+ def to_s(eol = false)
322
+ row_sep = eol ? self.class.options[:row_sep] : -""
178
323
 
179
- # Serializes a model object to a delimited string, using the delimiter
180
- # specified by {ClassMethods.delimiter}, and appends the string plus a
181
- # row separator to the specified file. Returns the model object.
182
- # This method is convenient when working with single model objects,
183
- # for example, appending a single entry to a log file. However, it is
184
- # not recommended for use with an array of model objects, due to the
185
- # overhead of opening and closing the file for each append.
186
- #
187
- # @example
188
- # Point = DumbDelimited[:x, :y, :z]
189
- # Point.new(1, 2, 3).append_to_file("out.txt") # == Point.new(1, 2, 3)
190
- # File.read("out.txt") # == "1,2,3\n"
191
- # Point.new(4, 5, 6).append_to_file("out.txt") # == Point.new(4, 5, 6)
192
- # File.read("out.txt") # == "1,2,3\n4,5,6\n"
193
- #
194
- # @param file [String, Pathname]
195
- # @return [self]
196
- def append_to_file(file)
197
- CSV.generate_line(self, self.class.options).append_to_file(file)
198
- self
324
+ CSV.generate(**self.class.options, row_sep: row_sep, write_headers: false) do |csv|
325
+ csv << self
326
+ end
199
327
  end
200
328
 
201
329
  end
@@ -1,3 +1,3 @@
1
1
  module DumbDelimited
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dumb_delimited
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Hefner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-16 00:00:00.000000000 Z
11
+ date: 2019-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: pleasant_path
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -116,8 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
102
  - !ruby/object:Gem::Version
117
103
  version: '0'
118
104
  requirements: []
119
- rubyforge_project:
120
- rubygems_version: 2.7.6
105
+ rubygems_version: 3.0.1
121
106
  signing_key:
122
107
  specification_version: 4
123
108
  summary: Library for unsophisticated delimited flat file IO