storable 0.9.pre.RC2 → 0.10.pre.RC1

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: 1fe040169d9300d29f3a00c5e46e74580a6f5a124b6dabda16ad3a8132d5a6eb
4
- data.tar.gz: 24de9dc3bf471ef05c6aad494482925131f0b00d3a4f3dff5f478eec4b655dee
3
+ metadata.gz: 1d4de380456e5e2160c14f50d89aca59f16663ee536f2c70c57fc60a012de4fa
4
+ data.tar.gz: da8b8b69b2c609d015a8a8a6a98dd7012b32e738a6249aea467956d3adfdfca8
5
5
  SHA512:
6
- metadata.gz: fdaa8dc26da7cf8163dcb1d5d6249a894816445fdf0309bff690e0fc70cc13b637bf3d9ae0557d5eec2a6cabe32986b318a683b3529b0fdee466b733e1c11afb
7
- data.tar.gz: 363d57e409178dac08aac9809768d6a1cfb7e4bccf2056be267da51718cc505219eb5a182a41cb3b87be2d5b4d569506dbbe473ee082e4ce8c3162f9cd9ccda7
6
+ metadata.gz: d06a4f6debd1580ff0eb700d6f0fc0c16fade5434448322fd9d576165723003dac7e22e32b7a05865e5ae169b40a5eddbe2e8f073f41694b8f84a81c3032997e
7
+ data.tar.gz: 52e61c82500333a12d4254d84d02b8580cdc71c3f0008e618a72d757a769d56f66d38553f306f9228291ea0f4a6ca6dca44081f7a70109aa617603d2dd371a3d
data/README.md CHANGED
@@ -78,8 +78,8 @@ Via Rubygems, one of:
78
78
  $ sudo gem install delano-storable --source http://gems.github.com/
79
79
 
80
80
  or via download:
81
- * storable-latest.tar.gz[http://github.com/delano/storable/tarball/latest]
82
- * storable-latest.zip[http://github.com/delano/storable/zipball/latest]
81
+ * [storable-latest.tar.gz](http://github.com/delano/storable/tarball/latest)
82
+ * [storable-latest.zip](http://github.com/delano/storable/zipball/latest)
83
83
 
84
84
 
85
85
  ## Prerequisites
@@ -90,20 +90,20 @@ or via download:
90
90
  ## Credits
91
91
 
92
92
  * Delano Mandelbaum (delano@solutious.com)
93
- * lib/proc_source.rb is based on http://github.com/imedo/background
93
+ * lib/proc_source.rb is based on [imedo/background](http://github.com/imedo/background)
94
94
  * OrderedHash implementation by Jan Molic
95
95
 
96
96
 
97
97
  ## Thanks
98
98
 
99
- * Pierre Riteau (priteau[https://github.com/priteau]) for bug fixes.
100
- * notro[https://github.com/priteau] for proc_source improvements.
99
+ * Pierre Riteau ([priteau](https://github.com/priteau)) for bug fixes.
100
+ * [notro](https://github.com/notro) for proc_source improvements.
101
101
 
102
102
 
103
103
  ## More Info
104
104
 
105
- * GitHub[http://github.com/delano/storable]
105
+ * [GitHub](http://github.com/delano/storable)
106
106
 
107
107
  ## License
108
108
 
109
- See: LICENSE.txt
109
+ See: [storable.gemspec](https://github.com/delano/storable/blob/main/storable.gemspec)
data/lib/core_ext.rb CHANGED
@@ -1,21 +1,14 @@
1
+ # frozen_string_literal: false
1
2
 
2
3
  #
3
4
  # RubyToken was removed in >= 2.7
4
5
  # Direct copy from Ruby 2.6.6 source
5
6
  #
6
-
7
- # frozen_string_literal: false
8
- #
9
7
  # irb/ruby-token.rb - ruby tokens
10
8
  # $Release Version: 0.9.6$
11
9
  # $Revision$
12
10
  # by Keiju ISHITSUKA(keiju@ruby-lang.org)
13
11
  #
14
- # --
15
- #
16
- #
17
- #
18
- # :stopdoc:
19
12
  module RubyToken
20
13
  EXPR_BEG = :EXPR_BEG
21
14
  EXPR_MID = :EXPR_MID
data/lib/storable.rb CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- YAJL_LOADED = begin
3
+ YAJL_LOADED = begin
4
4
  require 'yajl'
5
5
  true
6
6
  rescue LoadError
@@ -19,7 +19,7 @@ require 'fileutils'
19
19
  require 'time'
20
20
 
21
21
  unless defined?(Boolean)
22
- # Used in field definitions.
22
+ # Used in field definitions.
23
23
  #
24
24
  # field :name => Boolean
25
25
  #
@@ -27,47 +27,46 @@ unless defined?(Boolean)
27
27
  end
28
28
 
29
29
  # Storable makes data available in multiple formats and can
30
- # re-create objects from files. Fields are defined using the
31
- # Storable.field method which tells Storable the order and
30
+ # re-create objects from files. Fields are defined using the
31
+ # Storable.field method which tells Storable the order and
32
32
  # name.
33
33
  class Storable
34
34
  USE_ORDERED_HASH = (RUBY_VERSION =~ /^1.9/).nil?
35
- require 'proc_source'
35
+
36
36
  require 'storable/orderedhash' if USE_ORDERED_HASH
37
37
  unless defined?(SUPPORTED_FORMATS) # We can assume all are defined
38
38
  VERSION = "0.8.9"
39
- NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze
40
- SUPPORTED_FORMATS = [:tsv, :csv, :yaml, :json, :s, :string].freeze
39
+ NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze
40
+ SUPPORTED_FORMATS = [:tsv, :csv, :yaml, :json, :s, :string].freeze
41
41
  end
42
-
42
+
43
43
  @debug = false
44
44
  class << self
45
45
  attr_accessor :sensitive_fields, :field_names, :field_types, :field_opts, :debug
46
46
  end
47
-
47
+
48
48
  # Passes along fields to inherited classes
49
- def self.inherited(obj)
50
- unless Storable == self
49
+ def self.inherited(obj)
50
+ unless Storable == self
51
51
  obj.sensitive_fields = self.sensitive_fields.clone if !self.sensitive_fields.nil?
52
52
  obj.field_names = self.field_names.clone if !self.field_names.nil?
53
53
  obj.field_types = self.field_types.clone if !self.field_types.nil?
54
- end
55
- end
56
-
54
+ end
55
+ end
56
+
57
57
  # Accepts field definitions in the one of the follow formats:
58
58
  #
59
59
  # field :product
60
60
  # field :product => Integer
61
61
  # field :product do |val|
62
- # # modify val before it's stored.
62
+ # # modify val before it's stored.
63
63
  # end
64
64
  #
65
65
  # The order they're defined determines the order the will be output. The fields
66
66
  # data is available by the standard accessors, class.product and class.product= etc...
67
- # The value of the field will be cast to the type (if provided) when read from a file.
68
- # The value is not touched when the type is not provided.
67
+ # The value of the field will be cast to the type (if provided) when read from a file.
68
+ # The value is not touched when the type is not provided.
69
69
  def self.field(*args, &processor)
70
- # TODO: Examine casting from: http://codeforpeople.com/lib/ruby/fattr/fattr-1.0.3/
71
70
  field_definitions = {}
72
71
  if args.first.kind_of?(Hash)
73
72
  args.first.each_pair do |fname,klass|
@@ -80,10 +79,10 @@ class Storable
80
79
  elsif Hash === opts
81
80
  field_definitions[fname] = opts
82
81
  else
83
- raise ArgumentError, "Second argument must be a hash"
82
+ raise ArgumentError, "Second argument must be a hash"
84
83
  end
85
84
  end
86
-
85
+
87
86
  self.field_names ||= []
88
87
  self.field_types ||= {}
89
88
  self.field_opts ||= {}
@@ -91,21 +90,21 @@ class Storable
91
90
  self.field_names << fname
92
91
  self.field_opts[fname] = opts
93
92
  self.field_types[fname] = opts[:class] unless opts[:class].nil?
94
-
93
+
95
94
  # This processor automatically converts a Proc object
96
- # to a String of its source.
97
- processor = proc_processor if opts[:class] == Proc && processor.nil?
98
-
95
+ # to a String of its source.
96
+ # processor = proc_processor if opts[:class] == Proc && processor.nil?
97
+
99
98
  unless processor.nil?
100
99
  define_method("_storable_processor_#{fname}", &processor)
101
100
  end
102
-
101
+
103
102
  if method_defined?(fname) # don't redefine the getter method
104
103
  STDERR.puts "method exists: #{self}##{fname}" if Storable.debug
105
104
  else
106
- define_method(fname) do
105
+ define_method(fname) do
107
106
  ret = instance_variable_get("@#{fname}")
108
- if ret.nil?
107
+ if ret.nil?
109
108
  if opts[:default]
110
109
  ret = opts[:default]
111
110
  elsif opts[:meth]
@@ -115,63 +114,63 @@ class Storable
115
114
  ret
116
115
  end
117
116
  end
118
-
117
+
119
118
  if method_defined?("#{fname}=") # don't redefine the setter methods
120
119
  STDERR.puts "method exists: #{self}##{fname}=" if Storable.debug
121
120
  else
122
- define_method("#{fname}=") do |val|
121
+ define_method("#{fname}=") do |val|
123
122
  instance_variable_set("@#{fname}",val)
124
123
  end
125
124
  end
126
125
  end
127
126
  end
128
-
127
+
129
128
  def self.sensitive_fields(*args)
130
129
  @sensitive_fields ||= []
131
130
  @sensitive_fields.push *args unless args.empty?
132
131
  @sensitive_fields
133
132
  end
134
-
133
+
135
134
  def self.sensitive_field?(name)
136
135
  @sensitive_fields ||= []
137
136
  @sensitive_fields.member?(name)
138
137
  end
139
-
138
+
140
139
  def self.has_field?(n)
141
140
  field_names.member? n.to_sym
142
141
  end
143
142
  def has_field?(n)
144
143
  self.class.field_names.member? n.to_sym
145
144
  end
146
-
147
-
145
+
146
+
148
147
  # This value will be used as a default unless provided on-the-fly.
149
148
  # See SUPPORTED_FORMATS for available values.
150
149
  attr_reader :format
151
-
150
+
152
151
  # See SUPPORTED_FORMATS for available values
153
152
  def format=(v)
154
153
  v &&= v.to_sym
155
154
  raise "Unsupported format: #{v}" unless SUPPORTED_FORMATS.member?(v)
156
155
  @format = v
157
156
  end
158
-
157
+
159
158
  def postprocess
160
159
  end
161
-
160
+
162
161
  def sensitive?
163
162
  @storable_sensitive == true
164
163
  end
165
-
164
+
166
165
  def sensitive!
167
166
  @storable_sensitive = true
168
167
  end
169
-
168
+
170
169
  # Returns an array of field names defined by self.field
171
170
  def field_names
172
171
  self.class.field_names #|| self.class.ancestors.first.field_names
173
172
  end
174
- # Returns an array of field types defined by self.field. Fields that did
173
+ # Returns an array of field types defined by self.field. Fields that did
175
174
  # not receive a type are set to nil.
176
175
  def field_types
177
176
  self.class.field_types #|| self.class.ancestors.first.field_types
@@ -179,21 +178,21 @@ class Storable
179
178
  def sensitive_fields
180
179
  self.class.sensitive_fields #|| self.class.ancestors.first.sensitive_fields
181
180
  end
182
-
183
- # Dump the object data to the given format.
181
+
182
+ # Dump the object data to the given format.
184
183
  def dump(format=nil, with_titles=false)
185
184
  format &&= format.to_sym
186
185
  format ||= :s # as in, to_s
187
186
  raise "Format not defined (#{format})" unless SUPPORTED_FORMATS.member?(format)
188
- send("to_#{format}")
187
+ send("to_#{format}")
189
188
  end
190
-
189
+
191
190
  def to_string(*args)
192
191
  # TODO: sensitive?
193
192
  to_s(*args)
194
193
  end
195
-
196
- # Create a new instance of the object using data from file.
194
+
195
+ # Create a new instance of the object using data from file.
197
196
  def self.from_file(file_path, format='yaml')
198
197
  raise "Cannot read file (#{file_path})" unless File.exists?(file_path)
199
198
  raise "#{self} doesn't support from_#{format}" unless self.respond_to?("from_#{format}")
@@ -202,7 +201,7 @@ class Storable
202
201
  me.format = format
203
202
  me
204
203
  end
205
- # Write the object data to the given file.
204
+ # Write the object data to the given file.
206
205
  def to_file(file_path=nil, with_titles=true)
207
206
  raise "Cannot store to nil path" if file_path.nil?
208
207
  format = File.extname(file_path).tr('.', '')
@@ -210,7 +209,7 @@ class Storable
210
209
  format ||= @format
211
210
  Storable.write_file(file_path, dump(format, with_titles))
212
211
  end
213
-
212
+
214
213
  # Create a new instance of the object from a hash.
215
214
  def self.from_hash(from={})
216
215
  return nil if !from || from.empty?
@@ -220,22 +219,22 @@ class Storable
220
219
  new.from_hash(from)
221
220
  end
222
221
  end
223
-
222
+
224
223
  def init *args
225
224
  from_array *args
226
225
  end
227
-
226
+
228
227
  def initialize *args
229
228
  init *args
230
229
  end
231
-
230
+
232
231
  def from_array *from
233
232
  (self.field_names || []).each_with_index do |n,index|
234
233
  break if index >= from.size
235
234
  send("#{n}=", from[index])
236
235
  end
237
236
  end
238
-
237
+
239
238
  def self.from_array *from
240
239
  from = from.flatten.compact
241
240
  return nil if !from || from.empty?
@@ -244,7 +243,7 @@ class Storable
244
243
  me.postprocess
245
244
  me
246
245
  end
247
-
246
+
248
247
  def call(fname)
249
248
  unless field_types[fname.to_sym] == Proc &&
250
249
  Proc === self.send(fname)
@@ -252,16 +251,16 @@ class Storable
252
251
  end
253
252
  self.instance_eval &self.send(fname)
254
253
  end
255
-
254
+
256
255
  def from_hash(from={})
257
256
  fnames = field_names
258
-
257
+
259
258
  return from if fnames.nil? || fnames.empty?
260
259
  fnames.each_with_index do |fname,index|
261
260
  ftype = field_types[fname]
262
261
  value_orig = from[fname.to_s] || from[fname.to_s.to_sym]
263
262
  next if value_orig.nil?
264
-
263
+
265
264
  if ( ftype == String or ftype == Symbol ) && value_orig.to_s.empty?
266
265
  value = ''
267
266
  elsif ftype == Array
@@ -270,7 +269,7 @@ class Storable
270
269
  value = value_orig
271
270
  elsif !ftype.nil?
272
271
  value_orig = value_orig.first if Array === value_orig && value_orig.size == 1
273
-
272
+
274
273
  if [Time, DateTime].member?(ftype)
275
274
  value = ftype.parse(value_orig)
276
275
  elsif [TrueClass, FalseClass, Boolean].member?(ftype)
@@ -299,26 +298,26 @@ class Storable
299
298
  end
300
299
  end
301
300
  elsif ftype == Proc && String === value_orig
302
- value = Proc.from_string value_orig
301
+ value = Proc.new { "Procs can not be rehydrated as of v0.10" }
303
302
  end
304
303
  end
305
-
304
+
306
305
  value = value_orig if value.nil?
307
-
306
+
308
307
  if self.respond_to?("#{fname}=")
309
- self.send("#{fname}=", value)
308
+ self.send("#{fname}=", value)
310
309
  else
311
- self.instance_variable_set("@#{fname}", value)
310
+ self.instance_variable_set("@#{fname}", value)
312
311
  end
313
-
312
+
314
313
  end
315
314
 
316
315
  self.postprocess
317
316
  self
318
317
  end
319
-
318
+
320
319
  # Return the object data as a hash
321
- # +with_titles+ is ignored.
320
+ # +with_titles+ is ignored.
322
321
  def to_hash
323
322
  preprocess if respond_to? :preprocess
324
323
  tmp = USE_ORDERED_HASH ? Storable::OrderedHash.new : {}
@@ -328,7 +327,7 @@ class Storable
328
327
  v = self.send(fname)
329
328
  v = process(fname, v) if has_processor?(fname)
330
329
  if Array === v
331
- v = v.collect { |v2| v2.kind_of?(Storable) ? v2.to_hash : v2 }
330
+ v = v.collect { |v2| v2.kind_of?(Storable) ? v2.to_hash : v2 }
332
331
  end
333
332
  tmp[fname] = v.kind_of?(Storable) ? v.to_hash : v
334
333
  end
@@ -344,12 +343,12 @@ class Storable
344
343
  v = self.send(fname)
345
344
  v = process(fname, v) if has_processor?(fname)
346
345
  if Array === v
347
- v = v.collect { |v2| v2.kind_of?(Storable) ? v2.to_a : v2 }
346
+ v = v.collect { |v2| v2.kind_of?(Storable) ? v2.to_a : v2 }
348
347
  end
349
348
  v
350
349
  end
351
350
  end
352
-
351
+
353
352
  def to_json(*from, &blk)
354
353
  preprocess if respond_to? :preprocess
355
354
  hash = to_hash
@@ -358,11 +357,11 @@ class Storable
358
357
  ret
359
358
  elsif JSON_LOADED
360
359
  JSON.generate(hash, *from, &blk)
361
- else
360
+ else
362
361
  raise "no JSON parser loaded"
363
362
  end
364
363
  end
365
-
364
+
366
365
  def to_yaml(*from, &blk)
367
366
  preprocess if respond_to? :preprocess
368
367
  to_hash.to_yaml(*from, &blk)
@@ -371,22 +370,22 @@ class Storable
371
370
  def process(fname, val)
372
371
  self.send :"_storable_processor_#{fname}", val
373
372
  end
374
-
373
+
375
374
  def has_processor?(fname)
376
375
  self.respond_to? :"_storable_processor_#{fname}"
377
376
  end
378
-
379
- # Create a new instance of the object from YAML.
380
- # +from+ a YAML String or Array (split into by line).
377
+
378
+ # Create a new instance of the object from YAML.
379
+ # +from+ a YAML String or Array (split into by line).
381
380
  def self.from_yaml(*from)
382
381
  from_str = [from].flatten.compact.join('')
383
382
  hash = YAML::load(from_str)
384
383
  hash = from_hash(hash) if Hash === hash
385
384
  hash
386
385
  end
387
-
388
- # Create a new instance of the object from a JSON string.
389
- # +from+ a YAML String or Array (split into by line).
386
+
387
+ # Create a new instance of the object from a JSON string.
388
+ # +from+ a YAML String or Array (split into by line).
390
389
  def self.from_json(*from)
391
390
  from_str = [from].flatten.compact.join('')
392
391
  #from_str.force_encoding("ISO-8859-1")
@@ -402,11 +401,11 @@ class Storable
402
401
  hash[key.to_sym] = tmp[key]
403
402
  hash
404
403
  end
405
- hash_sym = from_hash(hash_sym) if hash_sym.kind_of?(Hash)
404
+ hash_sym = from_hash(hash_sym) if hash_sym.kind_of?(Hash)
406
405
  hash_sym
407
406
  end
408
-
409
- # Return the object data as a delimited string.
407
+
408
+ # Return the object data as a delimited string.
410
409
  # +with_titles+ specifiy whether to include field names (default: false)
411
410
  # +delim+ is the field delimiter.
412
411
  def to_delimited(with_titles=false, delim=',')
@@ -420,17 +419,17 @@ class Storable
420
419
  output = field_names.join(delim) << $/ << output if with_titles
421
420
  output
422
421
  end
423
- # Return the object data as a tab delimited string.
422
+ # Return the object data as a tab delimited string.
424
423
  # +with_titles+ specifiy whether to include field names (default: false)
425
424
  def to_tsv(with_titles=false)
426
425
  to_delimited(with_titles, "\t")
427
426
  end
428
- # Return the object data as a comma delimited string.
427
+ # Return the object data as a comma delimited string.
429
428
  # +with_titles+ specifiy whether to include field names (default: false)
430
429
  def to_csv(with_titles=false)
431
430
  to_delimited(with_titles, ',')
432
431
  end
433
- # Create a new instance from tab-delimited data.
432
+ # Create a new instance from tab-delimited data.
434
433
  # +from+ a JSON string split into an array by line.
435
434
  def self.from_tsv(from=[], sensitive=false)
436
435
  self.from_delimited(from, "\t", sensitive)
@@ -440,7 +439,7 @@ class Storable
440
439
  def self.from_csv(from=[], sensitive=false)
441
440
  self.from_delimited(from, ',', sensitive)
442
441
  end
443
-
442
+
444
443
  # Create a new instance of the object from a delimited string.
445
444
  # +from+ a JSON string split into an array by line.
446
445
  # +delim+ is the field delimiter.
@@ -448,48 +447,48 @@ class Storable
448
447
  return if from.empty?
449
448
  from = from.split($/) if String === from
450
449
  hash = {}
451
-
450
+
452
451
  fnames = sensitive ? (field_names-sensitive_fields) : field_names
453
452
  values = from[0].chomp.split(delim)
454
-
453
+
455
454
  fnames.each_with_index do |key,index|
456
455
  next unless values[index]
457
456
  hash[key.to_sym] = values[index]
458
457
  end
459
- hash = from_hash(hash) if hash.kind_of?(Hash)
458
+ hash = from_hash(hash) if hash.kind_of?(Hash)
460
459
  hash
461
460
  end
462
461
 
463
462
  def self.read_file_to_array(path)
464
463
  contents = []
465
464
  return contents unless File.exists?(path)
466
-
465
+
467
466
  open(path, 'r') do |l|
468
467
  contents = l.readlines
469
468
  end
470
469
 
471
470
  contents
472
471
  end
473
-
472
+
474
473
  def self.write_file(path, content, flush=true)
475
474
  write_or_append_file('w', path, content, flush)
476
475
  end
477
-
476
+
478
477
  def self.append_file(path, content, flush=true)
479
478
  write_or_append_file('a', path, content, flush)
480
479
  end
481
-
480
+
482
481
  def self.write_or_append_file(write_or_append, path, content = '', flush = true)
483
- #STDERR.puts "Writing to #{ path }..."
482
+ #STDERR.puts "Writing to #{ path }..."
484
483
  create_dir(File.dirname(path))
485
-
486
- open(path, write_or_append) do |f|
484
+
485
+ open(path, write_or_append) do |f|
487
486
  f.puts content
488
487
  f.flush if flush;
489
488
  end
490
489
  File.chmod(0600, path)
491
490
  end
492
-
491
+
493
492
  class Anonymous
494
493
  def initialize from
495
494
  @hash = from
@@ -501,7 +500,7 @@ class Storable
501
500
  @hash[meth.to_sym]
502
501
  end
503
502
  end
504
-
503
+
505
504
  end
506
505
 
507
506
 
@@ -517,13 +516,13 @@ class Storable
517
516
  #
518
517
  module DefaultProcessors
519
518
  # Replace a hash of Proc objects with a hash
520
- # of
521
- def hash_proc_processor
519
+ # of
520
+ def hash_proc_processor
522
521
  Proc.new do |procs|
523
522
  a = {}
524
523
  unless procs.nil?
525
- procs.each_pair { |n,v|
526
- a[n] = (Proc === v) ? v.source : v
524
+ procs.each_pair { |n,v|
525
+ a[n] = (Proc === v) ? v.source : v
527
526
  }
528
527
  end
529
528
  a
@@ -531,14 +530,14 @@ class Storable
531
530
  end
532
531
  def proc_processor
533
532
  Proc.new do |val|
534
- ret = (Proc === val) ? val.source : val
533
+ ret = (Proc === val) ? val.source : val
535
534
  ret
536
535
  end
537
536
  end
538
537
  # If the object already has a value for +@id+
539
538
  # use it, otherwise return the current digest.
540
539
  #
541
- # This allows an object to have a preset ID.
540
+ # This allows an object to have a preset ID.
542
541
  #
543
542
  def gibbler_id_processor
544
543
  Proc.new do |val|
data/storable.gemspec CHANGED
@@ -1,25 +1,20 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "storable"
3
- s.version = "0.9-RC2"
3
+ s.version = "0.10-RC1"
4
4
  s.summary = "Ruby classes as strings"
5
5
  s.description = "Storable: Marshal Ruby classes into and out of multiple formats (yaml, json, csv, tsv)"
6
6
  s.authors = ["Delano Mandelbaum"]
7
7
  s.email = "gems@solutious.com"
8
8
  s.homepage = "https://github.com/delano/storable/"
9
9
  s.licenses = ["MIT"] # https://spdx.org/licenses/MIT-Modern-Variant.html
10
+ s.executables = %w()
10
11
  s.files = %w(
11
12
  README.md
12
- Rakefile
13
- bin/example
14
- bin/tryouts
15
13
  lib/core_ext.rb
16
- lib/proc_source.rb
17
14
  lib/storable.rb
18
15
  lib/storable/orderedhash.rb
19
16
  storable.gemspec
20
17
  )
21
- s.executables = %w(
22
- )
23
18
  s.extra_rdoc_files = %w[README.md]
24
19
  s.rdoc_options = ["--line-numbers", "--title", s.summary, "--main", "README.md"]
25
20
  s.require_paths = %w[lib]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: storable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.pre.RC2
4
+ version: 0.10.pre.RC1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-04 00:00:00.000000000 Z
11
+ date: 2024-04-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Storable: Marshal Ruby classes into and out of multiple formats (yaml,
14
14
  json, csv, tsv)'
@@ -19,9 +19,7 @@ extra_rdoc_files:
19
19
  - README.md
20
20
  files:
21
21
  - README.md
22
- - Rakefile
23
22
  - lib/core_ext.rb
24
- - lib/proc_source.rb
25
23
  - lib/storable.rb
26
24
  - lib/storable/orderedhash.rb
27
25
  - storable.gemspec
@@ -29,7 +27,7 @@ homepage: https://github.com/delano/storable/
29
27
  licenses:
30
28
  - MIT
31
29
  metadata: {}
32
- post_install_message:
30
+ post_install_message:
33
31
  rdoc_options:
34
32
  - "--line-numbers"
35
33
  - "--title"
@@ -49,8 +47,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
49
47
  - !ruby/object:Gem::Version
50
48
  version: 1.3.1
51
49
  requirements: []
52
- rubygems_version: 3.2.14
53
- signing_key:
50
+ rubygems_version: 3.3.26
51
+ signing_key:
54
52
  specification_version: 4
55
53
  summary: Ruby classes as strings
56
54
  test_files: []
data/Rakefile DELETED
@@ -1,62 +0,0 @@
1
- require 'rubygems'
2
- require 'rake/clean'
3
- require 'rubygems/package_task'
4
- require 'fileutils'
5
- require 'rdoc/task'
6
- include FileUtils
7
-
8
- task :default => :package
9
-
10
-
11
- # CONFIG =============================================================
12
-
13
- # Change the following according to your needs
14
- README = "README.md"
15
- LICENSE = "LICENSE.txt"
16
-
17
- # Files and directories to be deleted when you run "rake clean"
18
- CLEAN.include [ 'pkg', '*.gem', '.config']
19
-
20
- # Virginia assumes your project and gemspec have the same name
21
- name = (Dir.glob('*.gemspec') || ['virginia']).first.split('.').first
22
- load "#{name}.gemspec"
23
- version = @spec.version
24
-
25
- # That's it! The following defaults should allow you to get started
26
- # on other things.
27
-
28
-
29
- # TESTS/SPECS =========================================================
30
-
31
- task :test do
32
- sh "try"
33
- end
34
-
35
- # INSTALL =============================================================
36
-
37
- Gem::PackageTask.new(@spec) do |p|
38
- p.need_tar = true if RUBY_PLATFORM !~ /mswin/
39
- end
40
-
41
- task :build => [ :test, :package ]
42
- task :release => [ :rdoc, :package ]
43
- task :install => [ :rdoc, :package ] do
44
- sh %{sudo gem install pkg/#{name}-#{version}.gem}
45
- end
46
- task :uninstall => [ :clean ] do
47
- sh %{sudo gem uninstall #{name}}
48
- end
49
-
50
-
51
- # RUBY DOCS TASK ==================================
52
-
53
- RDoc::Task.new do |t|
54
- t.rdoc_dir = 'doc'
55
- t.title = @spec.summary
56
- t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
57
- t.options << '--charset' << 'utf-8'
58
- t.rdoc_files.include(LICENSE)
59
- t.rdoc_files.include(README)
60
- #t.rdoc_files.include('bin/*')
61
- t.rdoc_files.include('lib/**/*.rb')
62
- end
data/lib/proc_source.rb DELETED
@@ -1,321 +0,0 @@
1
-
2
- #
3
- # Based on:
4
- # https://github.com/imedo/background
5
- # https://github.com/imedo/background_lite
6
- # With improvements by:
7
- # https://github.com/notro/storable
8
- #
9
-
10
- # RubyToken was removed in Ruby 2.7
11
- if RUBY_VERSION < "2.7"
12
- require 'irb/ruby-token'
13
- else
14
- require './lib/core_ext.rb'
15
- end
16
-
17
- require 'irb/ruby-lex'
18
- require 'pry'
19
- require 'stringio'
20
-
21
- SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
22
-
23
-
24
- class ProcString < String
25
- # Filename where the proc is defined
26
- attr_accessor :file
27
-
28
- # Range of lines where the proc is defined. e.g. (12..16)
29
- attr_accessor :lines
30
- attr_accessor :arity, :kind
31
-
32
- # Return a Proc object
33
- # If #lines and #file is specified, these are tied to the proc.
34
- def to_proc(kind="proc")
35
- if @file && @lines
36
- raise "#lines must be a range" unless @lines.kind_of? Range
37
- result = eval("#{kind} #{self}", binding, @file, @lines.min)
38
- else
39
- result = eval("#{kind} #{self}")
40
- end
41
- result.source = self
42
- result
43
- end
44
-
45
- # Return a lambda
46
- def to_lambda
47
- to_proc "lambda"
48
- end
49
- end
50
-
51
- class RubyToken::Token
52
- # These EXPR_BEG tokens don't have associated end tags
53
- FAKIES = [
54
- RubyToken::TkWHEN,
55
- RubyToken::TkELSIF,
56
- RubyToken::TkELSE,
57
- RubyToken::TkTHEN,
58
- ]
59
-
60
- def name
61
- @name ||= nil
62
- end
63
-
64
- def open_tag?
65
- return false if name.nil? || get_props.nil?
66
- is_open = (
67
- (get_props[1] == RubyToken::EXPR_BEG) &&
68
- (self.class.to_s !~ /_MOD/) && # ignore onliner if, unless, etc...
69
- (!FAKIES.member?(self.class))
70
- )
71
- is_open
72
- end
73
-
74
- def get_props
75
- RubyToken::TkReading2Token[name]
76
- end
77
-
78
- end
79
-
80
- # Based heavily on code from http://github.com/imedo/background
81
- # Big thanks to the imedo dev team!
82
- #
83
- module ProcSource
84
- def self.find(filename, start_line=1, block_only=true)
85
- lines, lexer = nil, nil
86
- retried = 0
87
- loop do
88
- lines = get_lines(filename, start_line)
89
- return nil if lines.nil?
90
- if !line_has_open?(lines.join) && start_line >= 0
91
- start_line -= 1 and retried +=1 and redo
92
- end
93
- lexer = RubyLex.new
94
- lexer.set_input(StringIO.new(lines.join))
95
- break
96
- end
97
-
98
- stoken, etoken, nesting = nil, nil, 0
99
-
100
- binding.pry
101
- if RUBY_VERSION < "2.7"
102
- tokens = lexer.instance_variable_get '@OP'
103
- else
104
- lexer.lex
105
- tokens = lexer.instance_variable_get '@tokens'
106
- end
107
-
108
- # tokens.each
109
-
110
- while (token = lexer.token) do
111
- if RubyToken::TkIDENTIFIER === token
112
- # nothing
113
- elsif token.open_tag? || RubyToken::TkfLBRACE === token
114
- nesting += 1
115
- stoken = token if nesting == 1
116
- elsif RubyToken::TkEND === token || RubyToken::TkRBRACE === token
117
- if nesting == 1
118
- etoken = token
119
- break
120
- end
121
- nesting -= 1
122
- elsif RubyToken::TkLBRACE === token
123
- nesting += 1
124
- elsif RubyToken::TkBITOR === token && stoken
125
- # nothing
126
- elsif RubyToken::TkNL === token && stoken && etoken
127
- break if nesting <= 0
128
- else
129
- # nothing
130
- end
131
- end
132
-
133
- lines = lines[stoken.line_no-1 .. etoken.line_no-1]
134
-
135
- # Remove the crud before the block definition.
136
- if block_only
137
- spaces = lines.last.match(/^\s+/)[0] rescue ''
138
- lines[0] = spaces << lines[0][stoken.char_no .. -1]
139
- end
140
- ps = ProcString.new lines.join
141
- ps.file = filename
142
- ps.lines = start_line .. start_line+etoken.line_no-1
143
- ps
144
- end
145
-
146
- # A hack for Ruby 1.9, otherwise returns true.
147
- #
148
- # Ruby 1.9 returns an incorrect line number
149
- # when a block is specified with do/end. It
150
- # happens b/c the line number returned by
151
- # Ruby 1.9 is based on the first line in the
152
- # block which contains a token (i.e. not a
153
- # new line or comment etc...).
154
- #
155
- # NOTE: This won't work in cases where the
156
- # incorrect line also contains a "do".
157
- #
158
- def self.line_has_open?(str)
159
- return true unless RUBY_VERSION >= '1.9' && RUBY_VERSION < '2.0'
160
- lexer = RubyLex.new
161
- lexer.set_input(StringIO.new(str))
162
- success = false
163
- while token = lexer.token
164
- case token
165
- when RubyToken::TkNL
166
- break
167
- when RubyToken::TkDO
168
- success = true
169
- when RubyToken::TkfLBRACE
170
- success = true
171
- when RubyToken::TkCONSTANT
172
- if token.name == "Proc" &&
173
- lexer.token.is_a?(RubyToken::TkDOT)
174
- method = lexer.token
175
- if method.is_a?(RubyToken::TkIDENTIFIER) &&
176
- method.name == "new"
177
- success = true
178
- end
179
- end
180
- end
181
- end
182
- success
183
- end
184
-
185
- def self.get_lines(filename, start_line = 1)
186
- case filename
187
- when nil
188
- nil
189
-
190
- # We're in irb
191
- when "(irb)"
192
- IRB.conf[:MAIN_CONTEXT].io.line(start_line .. -2)
193
-
194
- # Or an eval
195
- when /^\(eval.+\)$/
196
- EVAL_LINES__[filename][start_line .. -2]
197
-
198
- # Or most likely a .rb file
199
- else
200
- # Ruby already parsed this file? (see disclaimer above)
201
- if defined?(SCRIPT_LINES__) && SCRIPT_LINES__[filename]
202
- SCRIPT_LINES__[filename][(start_line - 1) .. -1]
203
-
204
- # If the file exists we're going to try reading it in
205
- elsif File.exist?(filename)
206
- begin
207
- File.readlines(filename)[(start_line - 1) .. -1]
208
- rescue
209
- nil
210
- end
211
- end
212
- end
213
- end
214
- end
215
-
216
- class Proc # :nodoc:
217
- attr_writer :source
218
- @@regexp = Regexp.new('^#<Proc:0x[0-9A-Fa-f]+@?\s*(.+):(\d+)(.+?)?>$')
219
-
220
- def source_descriptor
221
- return [@file, @line] if @file && @line
222
-
223
- source_location = nil
224
- if RUBY_VERSION >= '2.7'
225
- source_location = *self.source_location
226
- else
227
- inspection = inspect
228
- md = @@regexp.match(inspection)
229
- exmsg = 'Unable to parse proc inspect (%s)' % inspection
230
- raise Exception, exmsg if md.nil?
231
- source_location = md.captures
232
- end
233
-
234
- file, line = *source_location
235
- @file, @line = [file, line.to_i]
236
- end
237
-
238
- def source
239
- @source ||= ProcSource.find(*self.source_descriptor)
240
- end
241
-
242
- def line
243
- source_descriptor
244
- @line
245
- end
246
-
247
- def file
248
- source_descriptor
249
- @file
250
- end
251
-
252
- # Dump to Marshal format.
253
- # p = Proc.new { false }
254
- # Marshal.dump p
255
- def _dump(limit)
256
- raise "can't dump proc, #source is nil" if source.nil?
257
- str = Marshal.dump(source)
258
- str
259
- end
260
-
261
- # Load from Marshal format.
262
- # p = Proc.new { false }
263
- # Marshal.load Marshal.dump p
264
- def self._load(str)
265
- @source = Marshal.load(str)
266
- @source.to_proc
267
- end
268
-
269
- # Dump to JSON string
270
- def to_json(*args)
271
- raise "can't serialize proc, #source is nil" if source.nil?
272
- {
273
- 'json_class' => self.class.name,
274
- 'data' => [source.to_s, source.file, source.lines.min, source.lines.max]
275
- }.to_json#(*args)
276
- end
277
-
278
- def self.json_create(o)
279
- s, file, min, max = o['data']
280
- ps = ProcString.new s
281
- ps.file = file
282
- ps.lines = (min..max)
283
- ps.to_proc
284
- end
285
-
286
- # Create a Proc object from a string of Ruby code.
287
- # It's assumed the string contains do; end or { }.
288
- #
289
- # Proc.from_string("do; 2+2; end")
290
- #
291
- def self.from_string(str)
292
- eval "Proc.new #{str}"
293
- end
294
-
295
- end
296
-
297
- if $0 == __FILE__
298
- def store(&blk)
299
- @blk = blk
300
- end
301
-
302
- store do |blk|
303
- puts "Hello Rudy1"
304
- end
305
-
306
- a = Proc.new() { |a|
307
- puts "Hello Rudy2"
308
- }
309
-
310
- b = Proc.new() do |b|
311
- puts { "Hello Rudy3" } if true
312
- end
313
-
314
- puts @blk.inspect, @blk.source
315
- puts [a.inspect, a.source]
316
- puts b.inspect, b.source
317
-
318
- proc = @blk.source.to_proc
319
- proc.call(1)
320
- end
321
-