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

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
  SHA256:
3
- metadata.gz: 1fe040169d9300d29f3a00c5e46e74580a6f5a124b6dabda16ad3a8132d5a6eb
4
- data.tar.gz: 24de9dc3bf471ef05c6aad494482925131f0b00d3a4f3dff5f478eec4b655dee
3
+ metadata.gz: 9d468ae4b4c603f57f1181c2621c009468bd6a9675d6fd3d3fa93d31eaf6aa3c
4
+ data.tar.gz: 99a96fb2cb80836c7be1ccfd2d7ac7dae4adbefb90db6fd3a40376eb1ce43db6
5
5
  SHA512:
6
- metadata.gz: fdaa8dc26da7cf8163dcb1d5d6249a894816445fdf0309bff690e0fc70cc13b637bf3d9ae0557d5eec2a6cabe32986b318a683b3529b0fdee466b733e1c11afb
7
- data.tar.gz: 363d57e409178dac08aac9809768d6a1cfb7e4bccf2056be267da51718cc505219eb5a182a41cb3b87be2d5b4d569506dbbe473ee082e4ce8c3162f9cd9ccda7
6
+ metadata.gz: 625916584f044d82d6bab287ae2cad8218f02f358e622a142140349cea32c6b0152457f946bd41ac75c723a851633176bfce378468e65f8414ebe3d73c500cd7
7
+ data.tar.gz: 139253c3cd97dbf50d2c3a561ba26f6bb8fc2d892874d9cd70ac6c0eb5bf93a9569c2769ec4396ebe2837ada3fcd106b131d904afabbe92e57e9a0e74baae1e5
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-RC2"
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.RC2
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
-