storable 0.6.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|