storable 0.6.5 → 0.7.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.
- data/CHANGES.txt +16 -2
- data/lib/storable.rb +105 -54
- data/storable.gemspec +1 -1
- metadata +2 -2
data/CHANGES.txt
CHANGED
@@ -1,13 +1,27 @@
|
|
1
1
|
STORABLE, CHANGES
|
2
2
|
|
3
|
-
* TODO:
|
3
|
+
* TODO: Handle nested hashes and arrays.
|
4
|
+
* TODO: to_xml, see: http://codeforpeople.com/lib/ruby/xx/xx-2.0.0/README
|
5
|
+
|
6
|
+
#### 0.7.0 (2010-04-03) #############################
|
7
|
+
|
8
|
+
* FIXED: Default initialize method missed the last argument
|
9
|
+
* FIXED: Possible error in from_hash when a value is nil
|
10
|
+
* CHANGE: Remove unused "require 'fileutils'"
|
11
|
+
* CHANGE: field_types is now a Hash
|
12
|
+
* CHANGE: Set the instance variable if a setter method doesn't exist.
|
13
|
+
* CHANGE: Will grab the first element of an Array if there is only one
|
14
|
+
and a field type is defined that is not an Array.
|
15
|
+
* ADDED: Storable.debug
|
16
|
+
* ADDED: Boolean class (candy for TrueClass fields)
|
17
|
+
* ADDED: Automatically convert a Proc to a string of its source in to_hash
|
18
|
+
* ADDED: Support for Symbol field type
|
4
19
|
|
5
20
|
|
6
21
|
#### 0.6.5 (2010-03-23) #############################
|
7
22
|
|
8
23
|
* ADDED: Use Yajl if it's available.
|
9
24
|
|
10
|
-
|
11
25
|
#### 0.6.4 (2010-03-10) #############################
|
12
26
|
|
13
27
|
* FIXED: Don't pull the first value out of an array if there is only one element.
|
data/lib/storable.rb
CHANGED
@@ -4,8 +4,6 @@
|
|
4
4
|
#++
|
5
5
|
|
6
6
|
|
7
|
-
USE_ORDERED_HASH = (RUBY_VERSION =~ /^1.9/).nil?
|
8
|
-
|
9
7
|
YAJL_LOADED = begin
|
10
8
|
require 'yajl'
|
11
9
|
true
|
@@ -24,19 +22,12 @@ require 'yaml'
|
|
24
22
|
require 'fileutils'
|
25
23
|
require 'time'
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
procs.each_pair { |n,v|
|
34
|
-
a[n] = (Proc === v) ? v.source : v
|
35
|
-
}
|
36
|
-
a
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
25
|
+
unless defined?(Boolean)
|
26
|
+
# Used in field definitions.
|
27
|
+
#
|
28
|
+
# field :name => Boolean
|
29
|
+
#
|
30
|
+
class Boolean; end
|
40
31
|
end
|
41
32
|
|
42
33
|
# Storable makes data available in multiple formats and can
|
@@ -44,17 +35,18 @@ end
|
|
44
35
|
# Storable.field method which tells Storable the order and
|
45
36
|
# name.
|
46
37
|
class Storable
|
47
|
-
|
48
|
-
|
38
|
+
USE_ORDERED_HASH = (RUBY_VERSION =~ /^1.9/).nil?
|
39
|
+
require 'proc_source'
|
49
40
|
require 'storable/orderedhash' if USE_ORDERED_HASH
|
50
41
|
unless defined?(SUPPORTED_FORMATS) # We can assume all are defined
|
51
|
-
VERSION = "0.
|
42
|
+
VERSION = "0.7.0"
|
52
43
|
NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze
|
53
44
|
SUPPORTED_FORMATS = [:tsv, :csv, :yaml, :json, :s, :string].freeze
|
54
45
|
end
|
55
46
|
|
47
|
+
@debug = false
|
56
48
|
class << self
|
57
|
-
attr_accessor :field_names, :field_types
|
49
|
+
attr_accessor :field_names, :field_types, :debug
|
58
50
|
end
|
59
51
|
|
60
52
|
# This value will be used as a default unless provided on-the-fly.
|
@@ -88,18 +80,25 @@ class Storable
|
|
88
80
|
def self.field(args={}, &processor)
|
89
81
|
# TODO: Examine casting from: http://codeforpeople.com/lib/ruby/fattr/fattr-1.0.3/
|
90
82
|
args = {args => nil} unless args.kind_of?(Hash)
|
91
|
-
|
83
|
+
|
92
84
|
args.each_pair do |m,t|
|
93
85
|
self.field_names ||= []
|
94
|
-
self.field_types ||=
|
86
|
+
self.field_types ||= {}
|
95
87
|
self.field_names << m
|
96
|
-
self.field_types
|
88
|
+
self.field_types[m] = t unless t.nil?
|
89
|
+
|
90
|
+
# This processor automatically converts a Proc object
|
91
|
+
# to a String of its source.
|
92
|
+
processor = proc_processor if t == Proc && processor.nil?
|
97
93
|
|
98
94
|
unless processor.nil?
|
99
95
|
define_method("_storable_processor_#{m}", &processor)
|
100
96
|
end
|
101
97
|
|
102
|
-
|
98
|
+
if method_defined?(m) # don't redefine the accessor methods
|
99
|
+
STDERR.puts "method exists: #{self}##{m}" if Storable.debug
|
100
|
+
next
|
101
|
+
end
|
103
102
|
|
104
103
|
define_method(m) do instance_variable_get("@#{m}") end
|
105
104
|
define_method("#{m}=") do |val|
|
@@ -119,7 +118,7 @@ class Storable
|
|
119
118
|
# It's assumed that the order values matches the order
|
120
119
|
def initialize(*args)
|
121
120
|
(self.class.field_names || []).each_with_index do |n,index|
|
122
|
-
break if (index+1)
|
121
|
+
break if (index+1) > args.size
|
123
122
|
self.send("#{n}=", args[index])
|
124
123
|
end
|
125
124
|
end
|
@@ -137,7 +136,7 @@ class Storable
|
|
137
136
|
# Dump the object data to the given format.
|
138
137
|
def dump(format=nil, with_titles=false)
|
139
138
|
format &&= format.to_sym
|
140
|
-
format ||=
|
139
|
+
format ||= :s # as in, to_s
|
141
140
|
raise "Format not defined (#{format})" unless SUPPORTED_FORMATS.member?(format)
|
142
141
|
send("to_#{format}")
|
143
142
|
end
|
@@ -173,39 +172,44 @@ class Storable
|
|
173
172
|
|
174
173
|
def from_hash(from={})
|
175
174
|
fnames = field_names
|
176
|
-
fnames.each_with_index do |
|
177
|
-
|
175
|
+
fnames.each_with_index do |fname,index|
|
176
|
+
ftype = field_types[fname]
|
177
|
+
value_orig = from[fname] || from[fname.to_s]
|
178
178
|
|
179
|
-
|
180
|
-
# (sorry, me. It's just one of those days.) -- circa 2008-09-15
|
179
|
+
next if value_orig.nil?
|
181
180
|
|
182
|
-
if
|
183
|
-
value =
|
184
|
-
elsif
|
185
|
-
value =
|
186
|
-
|
187
|
-
|
188
|
-
|
181
|
+
if ftype == String && value_orig.to_s.empty?
|
182
|
+
value = ''
|
183
|
+
elsif ftype == Array
|
184
|
+
value = Array === value_orig ? value_orig : [value_orig]
|
185
|
+
elsif ftype == Hash
|
186
|
+
value = value_orig
|
187
|
+
elsif !ftype.nil?
|
188
|
+
value_orig = value_orig.first if Array === value_orig && value_orig.size == 1
|
189
189
|
|
190
|
-
if
|
191
|
-
value =
|
192
|
-
elsif
|
193
|
-
value =
|
194
|
-
elsif
|
195
|
-
value =
|
196
|
-
elsif
|
197
|
-
value =
|
198
|
-
elsif
|
199
|
-
value =
|
200
|
-
elsif
|
201
|
-
|
202
|
-
# and wait a while for an error in one of my other projects.
|
203
|
-
#value = field_types[index].from_hash(stored_value)
|
204
|
-
raise "Delano, delano, delano. Clean up Storable!"
|
190
|
+
if [Time, DateTime].member?(ftype)
|
191
|
+
value = ftype.parse(value_orig)
|
192
|
+
elsif [TrueClass, FalseClass, Boolean].member?(ftype)
|
193
|
+
value = (value_orig.to_s.upcase == "TRUE")
|
194
|
+
elsif ftype == Float
|
195
|
+
value = value_orig.to_f
|
196
|
+
elsif ftype == Integer
|
197
|
+
value = value_orig.to_i
|
198
|
+
elsif ftype == Symbol
|
199
|
+
value = value_orig.to_s.to_sym
|
200
|
+
elsif ftype == Proc && String === value_orig
|
201
|
+
value = Proc.from_string value_orig
|
205
202
|
end
|
206
203
|
end
|
204
|
+
|
205
|
+
value ||= value_orig
|
206
|
+
|
207
|
+
if self.respond_to?("#{fname}=")
|
208
|
+
self.send("#{fname}=", value)
|
209
|
+
else
|
210
|
+
self.instance_variable_set("@#{fname}", value)
|
211
|
+
end
|
207
212
|
|
208
|
-
self.send("#{key}=", value) if self.respond_to?("#{key}=")
|
209
213
|
end
|
210
214
|
|
211
215
|
self.postprocess
|
@@ -229,7 +233,11 @@ class Storable
|
|
229
233
|
def to_json(*from, &blk)
|
230
234
|
hash = to_hash
|
231
235
|
if YAJL_LOADED
|
232
|
-
Yajl::Encoder.encode(hash)
|
236
|
+
ret = Yajl::Encoder.encode(hash)
|
237
|
+
#raise "DELANO"
|
238
|
+
#ret.force_encoding("ISO-8859-1")
|
239
|
+
#p [:to, ret.encoding.name] if ret.respond_to?(:encoding)
|
240
|
+
ret
|
233
241
|
elsif JSON_LOADED
|
234
242
|
hash.to_json(*from, &blk)
|
235
243
|
else
|
@@ -262,8 +270,10 @@ class Storable
|
|
262
270
|
# +from+ a YAML String or Array (split into by line).
|
263
271
|
def self.from_json(*from)
|
264
272
|
from_str = [from].flatten.compact.join('')
|
273
|
+
#from_str.force_encoding("ISO-8859-1")
|
274
|
+
#p [:from, from_str.encoding.name] if from_str.respond_to?(:encoding)
|
265
275
|
if YAJL_LOADED
|
266
|
-
tmp = Yajl::Parser.parse(from_str)
|
276
|
+
tmp = Yajl::Parser.parse(from_str, :check_utf8 => false)
|
267
277
|
elsif JSON_LOADED
|
268
278
|
tmp = JSON::load(from_str)
|
269
279
|
else
|
@@ -367,3 +377,44 @@ class Storable
|
|
367
377
|
end
|
368
378
|
|
369
379
|
|
380
|
+
class Storable
|
381
|
+
# These methods can be used by Storable objects as
|
382
|
+
# custom field processors.
|
383
|
+
#
|
384
|
+
# e.g.
|
385
|
+
#
|
386
|
+
# class A < Storable
|
387
|
+
# field :name => String, &hash_proc_processor
|
388
|
+
# end
|
389
|
+
#
|
390
|
+
module DefaultProcessors
|
391
|
+
# Replace a hash of Proc objects with a hash
|
392
|
+
# of
|
393
|
+
def hash_proc_processor
|
394
|
+
Proc.new do |procs|
|
395
|
+
a = {}
|
396
|
+
procs.each_pair { |n,v|
|
397
|
+
a[n] = (Proc === v) ? v.source : v
|
398
|
+
}
|
399
|
+
a
|
400
|
+
end
|
401
|
+
end
|
402
|
+
def proc_processor
|
403
|
+
Proc.new do |val|
|
404
|
+
(Proc === val) ? val.source : val
|
405
|
+
end
|
406
|
+
end
|
407
|
+
# If the object already has a value for +@id+
|
408
|
+
# use it, otherwise return the current digest.
|
409
|
+
#
|
410
|
+
# This allows an object to have a preset ID.
|
411
|
+
#
|
412
|
+
def gibbler_id_processor
|
413
|
+
Proc.new do |val|
|
414
|
+
@id || self.gibbler
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
extend Storable::DefaultProcessors
|
419
|
+
end
|
420
|
+
|
data/storable.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "storable"
|
3
3
|
s.rubyforge_project = "storable"
|
4
|
-
s.version = "0.
|
4
|
+
s.version = "0.7.0"
|
5
5
|
s.summary = "Storable: Marshal Ruby classes into and out of multiple formats (yaml, json, csv, tsv)"
|
6
6
|
s.description = s.summary
|
7
7
|
s.author = "Delano Mandelbaum"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: storable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-03
|
12
|
+
date: 2010-04-03 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|