storable 0.5.8 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/CHANGES.txt +6 -0
  2. data/lib/storable.rb +62 -27
  3. data/storable.gemspec +1 -1
  4. metadata +3 -3
@@ -1,5 +1,11 @@
1
1
  STORABLE, CHANGES
2
2
 
3
+ #### 0.6.0 (2009-11-27) #############################
4
+
5
+ * FIXED: Undefined @@field_names error when no fields specified
6
+ * ADDED: Support for field output processors
7
+ * ADDED: Storable::DefaultProcessors
8
+
3
9
 
4
10
  #### 0.5.8 (2009-10-06) #############################
5
11
 
@@ -4,7 +4,7 @@
4
4
  #++
5
5
 
6
6
 
7
- USE_ORDERED_HASH = (RUBY_VERSION =~ /1.9/).nil?
7
+ USE_ORDERED_HASH = (RUBY_VERSION =~ /^1.9/).nil?
8
8
 
9
9
  begin
10
10
  require 'json'
@@ -15,19 +15,40 @@ end
15
15
  require 'yaml'
16
16
  require 'fileutils'
17
17
  require 'time'
18
-
18
+
19
+
20
+ class Storable
21
+ module DefaultProcessors
22
+ def hash_proc_processor
23
+ Proc.new do |procs|
24
+ a = {}
25
+ procs.each_pair { |n,v|
26
+ a[n] = (Proc === v) ? v.source : v
27
+ }
28
+ a
29
+ end
30
+ end
31
+ end
32
+ end
33
+
19
34
  # Storable makes data available in multiple formats and can
20
35
  # re-create objects from files. Fields are defined using the
21
36
  # Storable.field method which tells Storable the order and
22
37
  # name.
23
38
  class Storable
39
+ extend Storable::DefaultProcessors
40
+
24
41
  require 'storable/orderedhash' if USE_ORDERED_HASH
25
42
  unless defined?(SUPPORTED_FORMATS) # We can assume all are defined
26
- VERSION = "0.5.8"
43
+ VERSION = "0.6.0"
27
44
  NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze
28
45
  SUPPORTED_FORMATS = [:tsv, :csv, :yaml, :json, :s, :string].freeze
29
46
  end
30
47
 
48
+ class << self
49
+ attr_accessor :field_names, :field_types
50
+ end
51
+
31
52
  # This value will be used as a default unless provided on-the-fly.
32
53
  # See SUPPORTED_FORMATS for available values.
33
54
  attr_reader :format
@@ -48,23 +69,29 @@ class Storable
48
69
  #
49
70
  # field :product
50
71
  # field :product => Integer
72
+ # field :product do |val|
73
+ # # modify val before it's stored.
74
+ # end
51
75
  #
52
76
  # The order they're defined determines the order the will be output. The fields
53
77
  # data is available by the standard accessors, class.product and class.product= etc...
54
78
  # The value of the field will be cast to the type (if provided) when read from a file.
55
79
  # The value is not touched when the type is not provided.
56
- def self.field(args={})
80
+ def self.field(args={}, &processor)
57
81
  # TODO: Examine casting from: http://codeforpeople.com/lib/ruby/fattr/fattr-1.0.3/
58
82
  args = {args => nil} unless args.kind_of?(Hash)
59
83
 
60
84
  args.each_pair do |m,t|
85
+ self.field_names ||= []
86
+ self.field_types ||= []
87
+ self.field_names << m
88
+ self.field_types << t unless t.nil?
61
89
 
62
- [[:@@field_names, m], [:@@field_types, t]].each do |tuple|
63
- class_variable_set(tuple[0], []) unless class_variable_defined?(tuple[0])
64
- class_variable_set(tuple[0], class_variable_get(tuple[0]) << tuple[1])
90
+ unless processor.nil?
91
+ define_method("_storable_processor_#{m}", &processor)
65
92
  end
66
93
 
67
- next if method_defined?(m)
94
+ next if method_defined?(m) # don't refine the accessor methods
68
95
 
69
96
  define_method(m) do instance_variable_get("@#{m}") end
70
97
  define_method("#{m}=") do |val|
@@ -80,23 +107,15 @@ class Storable
80
107
  self.class.field_names.member? n.to_sym
81
108
  end
82
109
 
83
- # Returns an array of field names defined by self.field
84
- def self.field_names
85
- class_variable_get(:@@field_names)
86
- end
110
+
87
111
  # Returns an array of field names defined by self.field
88
112
  def field_names
89
- self.class.send(:class_variable_get, :@@field_names)
90
- end
91
- # Returns an array of field types defined by self.field. Fields that did
92
- # not receive a type are set to nil.
93
- def self.field_types
94
- class_variable_get(:@@field_types)
113
+ self.class.field_names
95
114
  end
96
115
  # Returns an array of field types defined by self.field. Fields that did
97
116
  # not receive a type are set to nil.
98
117
  def field_types
99
- self.class.send(:class_variable_get, :@@field_types)
118
+ self.class.field_types
100
119
  end
101
120
 
102
121
  # Dump the object data to the given format.
@@ -185,22 +204,40 @@ class Storable
185
204
  def to_hash
186
205
  tmp = USE_ORDERED_HASH ? Storable::OrderedHash.new : {}
187
206
  field_names.each do |fname|
188
- tmp[fname] = self.send(fname)
207
+ v = self.send(fname)
208
+ v = process(fname, v) if has_processor?(fname)
209
+ if Array === v
210
+ v = v.collect { |v2| v2.kind_of?(Storable) ? v2.to_hash : v2 }
211
+ end
212
+ tmp[fname] = v.kind_of?(Storable) ? v.to_hash : v
189
213
  end
190
214
  tmp
191
215
  end
192
216
 
217
+ def to_json(*from, &blk)
218
+ to_hash.to_json(*from, &blk)
219
+ end
220
+
221
+ def to_yaml(*from, &blk)
222
+ to_hash.to_yaml(*from, &blk)
223
+ end
224
+
225
+ def process(fname, val)
226
+ self.send :"_storable_processor_#{fname}", val
227
+ end
228
+
229
+ def has_processor?(fname)
230
+ self.respond_to? :"_storable_processor_#{fname}"
231
+ end
232
+
193
233
  # Create a new instance of the object from YAML.
194
234
  # +from+ a YAML String or Array (split into by line).
195
235
  def self.from_yaml(*from)
196
236
  from_str = [from].flatten.compact.join('')
197
237
  hash = YAML::load(from_str)
198
- hash = from_hash(hash) if hash.kind_of?(Hash)
238
+ hash = from_hash(hash) if Hash === hash
199
239
  hash
200
240
  end
201
- def to_yaml
202
- to_hash.to_yaml
203
- end
204
241
 
205
242
  # Create a new instance of the object from a JSON string.
206
243
  # +from+ a YAML String or Array (split into by line).
@@ -214,9 +251,6 @@ class Storable
214
251
  hash_sym = from_hash(hash_sym) if hash_sym.kind_of?(Hash)
215
252
  hash_sym
216
253
  end
217
- def to_json(with_titles=true)
218
- to_hash.to_json
219
- end
220
254
 
221
255
  # Return the object data as a delimited string.
222
256
  # +with_titles+ specifiy whether to include field names (default: false)
@@ -307,3 +341,4 @@ class Storable
307
341
  end
308
342
  end
309
343
 
344
+
@@ -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.5.8"
4
+ s.version = "0.6.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.5.8
4
+ version: 0.6.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: 2009-10-08 00:00:00 -04:00
12
+ date: 2009-11-27 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -58,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
58
  requirements: []
59
59
 
60
60
  rubyforge_project: storable
61
- rubygems_version: 1.3.2
61
+ rubygems_version: 1.3.5
62
62
  signing_key:
63
63
  specification_version: 3
64
64
  summary: "Storable: Marshal Ruby classes into and out of multiple formats (yaml, json, csv, tsv)"