storable 0.7.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/CHANGES.txt +10 -0
  2. data/README.rdoc +25 -8
  3. data/lib/storable.rb +74 -33
  4. data/storable.gemspec +1 -1
  5. metadata +17 -5
data/CHANGES.txt CHANGED
@@ -3,6 +3,16 @@ STORABLE, CHANGES
3
3
  * TODO: Handle nested hashes and arrays.
4
4
  * TODO: to_xml, see: http://codeforpeople.com/lib/ruby/xx/xx-2.0.0/README
5
5
 
6
+ #### 0.8.0 (2010-07-28) #############################
7
+
8
+ * FIXED: from_delimited now gracefully handles String input by splitting it by $/
9
+ * CHANGE: Removed field name magic from from_delimited
10
+ * CHANGE: Converted to Tryouts 2
11
+ * ADDED: Support for sensitive fields
12
+ * ADDED: Supports inheritance
13
+ * ADDED: Storable#to_array
14
+
15
+
6
16
  #### 0.7.4 (2010-05-01) #############################
7
17
 
8
18
  * FIXED: Check separately if getter and setter methods are already defined
data/README.rdoc CHANGED
@@ -26,6 +26,23 @@ Marshal Ruby classes into and out of multiple formats (yaml, json, csv, tsv)
26
26
  puts mac2.position.class # => Fixnum
27
27
 
28
28
 
29
+ == Sensitive Fields
30
+
31
+ require 'storable'
32
+
33
+ class Calc < Storable
34
+ field :three
35
+ field :two
36
+ field :one
37
+ sensitive_fields :three
38
+ end
39
+
40
+ calc = Calc.new 3, 2, 1
41
+ calc.to_a # => [3, 2, 1]
42
+ calc.sensitive!
43
+ calc.to_a # => [2, 1]
44
+
45
+
29
46
  == Storing Procs
30
47
 
31
48
  Storable can also marshal Proc objects to and from their actual source code.
@@ -38,18 +55,18 @@ Storable can also marshal Proc objects to and from their actual source code.
38
55
  field :calculate => Proc
39
56
  end
40
57
 
41
- mat1 = Maths.new 2.0, 3.0
42
- mat1.calculate = Proc.new { @x * @y }
43
-
44
- mat1.calculate.source # => "{ @x * @y }"
45
- mat1.call :calculate # => 6.0
58
+ m1 = Maths.new 2.0, 3.0
59
+ m1.calculate = Proc.new { @x * @y }
46
60
 
47
- dump = mat1.to_json
61
+ m1.calculate.source # => "{ @x * @y }"
62
+ m1.call :calculate # => 6.0
48
63
 
49
- mat2 = Maths.from_json dump
50
- mat2.call :calculate # => 6.0
64
+ dump = m1.to_json
51
65
 
66
+ m2 = Maths.from_json dump
67
+ m2.call :calculate # => 6.0
52
68
 
69
+
53
70
  Anything is possible when you keep your mind open and you use Ruby.
54
71
 
55
72
 
data/lib/storable.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  #--
2
2
  # TODO: Handle nested hashes and arrays.
3
3
  # TODO: to_xml, see: http://codeforpeople.com/lib/ruby/xx/xx-2.0.0/README
4
+ # TODO: from_args([HASH or ordered params])
4
5
  #++
5
6
 
6
7
 
@@ -39,32 +40,25 @@ class Storable
39
40
  require 'proc_source'
40
41
  require 'storable/orderedhash' if USE_ORDERED_HASH
41
42
  unless defined?(SUPPORTED_FORMATS) # We can assume all are defined
42
- VERSION = "0.7.4"
43
+ VERSION = "0.8.0"
43
44
  NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze
44
45
  SUPPORTED_FORMATS = [:tsv, :csv, :yaml, :json, :s, :string].freeze
45
46
  end
46
47
 
47
48
  @debug = false
48
49
  class << self
49
- attr_accessor :field_names, :field_types, :debug
50
+ attr_accessor :sensitive_fields, :field_names, :field_types, :debug
50
51
  end
51
52
 
52
- # This value will be used as a default unless provided on-the-fly.
53
- # See SUPPORTED_FORMATS for available values.
54
- attr_reader :format
55
-
56
- # See SUPPORTED_FORMATS for available values
57
- def format=(v)
58
- v &&= v.to_sym
59
- raise "Unsupported format: #{v}" unless SUPPORTED_FORMATS.member?(v)
60
- @format = v
61
- end
62
-
63
- def postprocess
64
- end
65
-
66
- # TODO: from_args([HASH or ordered params])
67
-
53
+ # Passes along fields to inherited classes
54
+ def self.inherited(obj)
55
+ unless Storable == self
56
+ obj.sensitive_fields = self.sensitive_fields.clone if !self.sensitive_fields.nil?
57
+ obj.field_names = self.field_names.clone if !self.field_names.nil?
58
+ obj.field_types = self.field_types.clone if !self.field_types.nil?
59
+ end
60
+ end
61
+
68
62
  # Accepts field definitions in the one of the follow formats:
69
63
  #
70
64
  # field :product
@@ -80,10 +74,10 @@ class Storable
80
74
  def self.field(args={}, &processor)
81
75
  # TODO: Examine casting from: http://codeforpeople.com/lib/ruby/fattr/fattr-1.0.3/
82
76
  args = {args => nil} unless args.kind_of?(Hash)
83
-
77
+
78
+ self.field_names ||= []
79
+ self.field_types ||= {}
84
80
  args.each_pair do |m,t|
85
- self.field_names ||= []
86
- self.field_types ||= {}
87
81
  self.field_names << m
88
82
  self.field_types[m] = t unless t.nil?
89
83
 
@@ -113,6 +107,17 @@ class Storable
113
107
  end
114
108
  end
115
109
 
110
+ def self.sensitive_fields(*args)
111
+ @sensitive_fields ||= []
112
+ @sensitive_fields.push *args unless args.empty?
113
+ @sensitive_fields
114
+ end
115
+
116
+ def self.sensitive_field?(name)
117
+ @sensitive_fields ||= []
118
+ @sensitive_fields.member?(name)
119
+ end
120
+
116
121
  def self.has_field?(n)
117
122
  field_names.member? n.to_sym
118
123
  end
@@ -120,6 +125,11 @@ class Storable
120
125
  self.class.field_names.member? n.to_sym
121
126
  end
122
127
 
128
+
129
+ # This value will be used as a default unless provided on-the-fly.
130
+ # See SUPPORTED_FORMATS for available values.
131
+ attr_reader :format
132
+
123
133
  # +args+ is a list of values to set amongst the fields.
124
134
  # It's assumed that the order values matches the order
125
135
  def initialize(*args)
@@ -129,7 +139,25 @@ class Storable
129
139
  end
130
140
  preprocess if respond_to?(:preprocess)
131
141
  end
132
-
142
+
143
+ # See SUPPORTED_FORMATS for available values
144
+ def format=(v)
145
+ v &&= v.to_sym
146
+ raise "Unsupported format: #{v}" unless SUPPORTED_FORMATS.member?(v)
147
+ @format = v
148
+ end
149
+
150
+ def postprocess
151
+ end
152
+
153
+ def sensitive?
154
+ @storable_sensitive == true
155
+ end
156
+
157
+ def sensitive!
158
+ @storable_sensitive = true
159
+ end
160
+
133
161
  # Returns an array of field names defined by self.field
134
162
  def field_names
135
163
  self.class.field_names
@@ -139,7 +167,10 @@ class Storable
139
167
  def field_types
140
168
  self.class.field_types
141
169
  end
142
-
170
+ def sensitive_fields
171
+ self.class.sensitive_fields
172
+ end
173
+
143
174
  # Dump the object data to the given format.
144
175
  def dump(format=nil, with_titles=false)
145
176
  format &&= format.to_sym
@@ -149,6 +180,7 @@ class Storable
149
180
  end
150
181
 
151
182
  def to_string(*args)
183
+ # TODO: sensitive?
152
184
  to_s(*args)
153
185
  end
154
186
 
@@ -251,11 +283,13 @@ class Storable
251
283
  self.postprocess
252
284
  self
253
285
  end
286
+
254
287
  # Return the object data as a hash
255
288
  # +with_titles+ is ignored.
256
289
  def to_hash
257
290
  tmp = USE_ORDERED_HASH ? Storable::OrderedHash.new : {}
258
291
  field_names.each do |fname|
292
+ next if sensitive? && self.class.sensitive_field?(fname)
259
293
  v = self.send(fname)
260
294
  v = process(fname, v) if has_processor?(fname)
261
295
  if Array === v
@@ -265,10 +299,23 @@ class Storable
265
299
  end
266
300
  tmp
267
301
  end
302
+
303
+ def to_array
304
+ fields = sensitive? ? (field_names-sensitive_fields) : field_names
305
+ fields.collect do |fname|
306
+ next if sensitive? && self.class.sensitive_field?(fname)
307
+ v = self.send(fname)
308
+ v = process(fname, v) if has_processor?(fname)
309
+ if Array === v
310
+ v = v.collect { |v2| v2.kind_of?(Storable) ? v2.to_a : v2 }
311
+ end
312
+ v
313
+ end
314
+ end
268
315
 
269
316
  def to_json(*from, &blk)
270
317
  hash = to_hash
271
- if YAJL_LOADED
318
+ if YAJL_LOADED # set by Storable
272
319
  ret = Yajl::Encoder.encode(hash)
273
320
  #raise "DELANO"
274
321
  #ret.force_encoding("ISO-8859-1")
@@ -361,17 +408,11 @@ class Storable
361
408
  # +delim+ is the field delimiter.
362
409
  def self.from_delimited(from=[],delim=',')
363
410
  return if from.empty?
364
- # We grab an instance of the class so we can
411
+ from = from.split($/) if String === from
365
412
  hash = {}
366
413
 
367
- fnames = values = []
368
- if (from.size > 1 && !from[1].empty?)
369
- fnames = from[0].chomp.split(delim)
370
- values = from[1].chomp.split(delim)
371
- else
372
- fnames = self.field_names
373
- values = from[0].chomp.split(delim)
374
- end
414
+ fnames = self.field_names
415
+ values = from[0].chomp.split(delim)
375
416
 
376
417
  fnames.each_with_index do |key,index|
377
418
  next unless values[index]
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.7.4"
4
+ s.version = "0.8.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,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: storable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.4
4
+ hash: 63
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 8
9
+ - 0
10
+ version: 0.8.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Delano Mandelbaum
@@ -9,7 +15,7 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-05-01 00:00:00 -04:00
18
+ date: 2010-07-28 00:00:00 -04:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
@@ -45,21 +51,27 @@ rdoc_options:
45
51
  require_paths:
46
52
  - lib
47
53
  required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
48
55
  requirements:
49
56
  - - ">="
50
57
  - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
51
61
  version: "0"
52
- version:
53
62
  required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
54
64
  requirements:
55
65
  - - ">="
56
66
  - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
57
70
  version: "0"
58
- version:
59
71
  requirements: []
60
72
 
61
73
  rubyforge_project: storable
62
- rubygems_version: 1.3.5
74
+ rubygems_version: 1.3.7
63
75
  signing_key:
64
76
  specification_version: 3
65
77
  summary: "Storable: Marshal Ruby classes into and out of multiple formats (yaml, json, csv, tsv)"