obfusk-data 0.0.2.SNAPSHOT.20130212031255 → 0.0.2.SNAPSHOT.20130213231507

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  File : README.md
4
4
  Maintainer : Felix C. Stegerman <flx@obfusk.net>
5
- Date : 2013-02-11
5
+ Date : 2013-02-13
6
6
 
7
7
  Copyright : Copyright (C) 2013 Felix C. Stegerman
8
8
  Version : 0.0.2.SNAPSHOT
@@ -14,9 +14,27 @@
14
14
 
15
15
  [rb-]obfusk-data - data validation combinator library for ruby
16
16
 
17
+ https://github.com/obfusk/clj-obfusk-data in ruby.
18
+
17
19
  ...
18
20
 
19
- https://github.com/obfusk/clj-obfusk-data in ruby.
21
+ ### ValidHash vs UnsafeValidHash
22
+
23
+ A ValidHash is always valid: modifications are rolled back if they
24
+ made it invalid.
25
+
26
+ An UnsafeValidHash may become invalid: modifications are always
27
+ performed, even if they make it invalid.
28
+
29
+ A ValidHash is therefore (probably) less efficient than an
30
+ UnsafeValidHash, but never becomes invalid. Choose wisely.
31
+
32
+ []: }}}1
33
+
34
+ ## Examples
35
+ []: {{{1
36
+
37
+ []: {{{2
20
38
 
21
39
  ```ruby
22
40
  isa = ->(cls, obj) { cls === obj } .curry
@@ -51,32 +69,68 @@ Obfusk::Data.valid? tree,
51
69
  # => true
52
70
  ```
53
71
 
72
+ []: }}}2
73
+
74
+ []: {{{2
75
+
54
76
  ```ruby
55
- class X < Obfusk::Data::ValidHash
56
- data do
57
- field :spam, []
58
- end
77
+ class Foo < Obfusk::Data::ValidHamster
78
+ data { field :foo, [] }
59
79
  end
60
80
 
61
- class Y < Obfusk::Data::ValidHamster
62
- data do
63
- field :spam, []
64
- end
81
+ x = Foo.new foo: 'ok'
82
+
83
+ x.put :invalid, 'oops'
84
+ # ---> Obfusk::Data::Valid::InvalidError
85
+
86
+ Foo.new
87
+ # ---> Obfusk::Data::Valid::InvalidError
88
+ ```
89
+
90
+ []: }}}2
91
+
92
+ []: {{{2
93
+
94
+ ```ruby
95
+ class Bar < Obfusk::Data::ValidHash
96
+ data { field :bar, [] }
65
97
  end
66
98
 
67
- x = X.new spam: 99; x[:spam] = 88
68
- # OK
99
+ y = Bar.new bar: 'ok'
100
+ y[:bar] = 'also ok'
69
101
 
70
- X.new
71
- # raises Obfusk::Data::ValidHash::InvalidError
102
+ begin
103
+ y[:invalid] = 'oops'
104
+ rescue Obfusk::Data::Valid::InvalidError
105
+ y.valid? # => true
106
+ y[:invalid] # => nil
107
+ end
108
+ ```
72
109
 
73
- y = Y.new spam: 'yuck!'
74
- # OK
110
+ []: }}}2
75
111
 
76
- Y.put :invalid, 'oops.'
77
- # raises Obfusk::Data::ValidHamster::InvalidError
112
+ []: {{{2
113
+
114
+ ```ruby
115
+ class Baz < Obfusk::Data::UnsafeValidHash
116
+ data { field :baz, [] }
117
+ end
118
+
119
+ z = Baz.new baz: 'ok'
120
+ c = z.dup
121
+
122
+ begin
123
+ z[:invalid] = 'oops'
124
+ rescue Obfusk::Data::Valid::InvalidError
125
+ z.valid? # => false
126
+ c.valid? # => true
127
+ z[:invalid] # => 'oops'
128
+ c[:invalid] # => nil
129
+ end
78
130
  ```
79
131
 
132
+ []: }}}2
133
+
80
134
  []: }}}1
81
135
 
82
136
  ## Specs & Docs
@@ -2,59 +2,47 @@
2
2
  #
3
3
  # File : obfusk/data/hamster.rb
4
4
  # Maintainer : Felix C. Stegerman <flx@obfusk.net>
5
- # Date : 2013-02-11
5
+ # Date : 2013-02-13
6
6
  #
7
7
  # Copyright : Copyright (C) 2013 Felix C. Stegerman
8
8
  # Licence : GPLv2 or EPLv1
9
9
  #
10
10
  # -- ; }}}1
11
11
 
12
- require 'obfusk/data/base'
12
+ require 'obfusk/data/valid'
13
13
 
14
14
  module Obfusk
15
15
  module Data
16
16
 
17
17
  # @todo document
18
- # @note
19
- # getting this to work depends on Hamster implementation details
20
- # as well as some black magic ;-(
18
+ # @note depends on Hamster implementation details !!!
21
19
  class ValidHamster < Hamster::Hash # {{{1
22
20
 
23
- include Base
21
+ include Valid
24
22
 
25
- class InvalidError < RuntimeError; end
26
-
27
- def self.__from_hamster (x)
28
- data = x.instance_eval { [@trie, @default] }
29
- y = allocate
30
- y.instance_eval { @trie, @default = data }
31
- y
32
- end
33
-
34
- def self.__to_hamster (x)
35
- data = x.instance_eval { [@trie, @default] }
36
- y = Hamster::Hash.allocate
37
- y.instance_eval { @trie, @default = data }
38
- y
23
+ def self.new (pairs = {}, &b)
24
+ @empty ||= super()
25
+ x = b ? super(&b) : @empty
26
+ pairs.empty? ? x.validate! : x.merge_hash(pairs)
39
27
  end
40
28
 
41
- def self.new (*a, &b)
42
- x = __from_hamster Hamster::Hash.new(*a, &b)
43
- x.validate!; x
29
+ def self.empty
30
+ @empty ? @empty.validate! : new
44
31
  end
45
32
 
46
- def self.empty
47
- x = @empty ||= new; x.validate!; x
33
+ def except (*keys)
34
+ trie = keys.reduce(@trie) { |t, k| t.delete k }
35
+ transform_unless(trie.equal? @trie) { @trie = trie }
48
36
  end
49
37
 
50
- def except (*a, &b)
51
- y = self.class.__to_hamster self
52
- x = self.class.__from_hamster y.except(*a, &b)
53
- x.validate!; x
38
+ def merge_hash (pairs)
39
+ transform_unless(pairs.empty?) {
40
+ @trie = pairs.reduce(@trie) { |t, p| t.put *p }
41
+ }
54
42
  end
55
43
 
56
- def transform (*a, &b)
57
- x = super; x.validate!; x
44
+ def transform (&b)
45
+ super.validate!
58
46
  end
59
47
 
60
48
  end # }}}1
@@ -2,68 +2,130 @@
2
2
  #
3
3
  # File : obfusk/data/hash.rb
4
4
  # Maintainer : Felix C. Stegerman <flx@obfusk.net>
5
- # Date : 2013-02-11
5
+ # Date : 2013-02-13
6
6
  #
7
7
  # Copyright : Copyright (C) 2013 Felix C. Stegerman
8
8
  # Licence : GPLv2 or EPLv1
9
9
  #
10
10
  # -- ; }}}1
11
11
 
12
- require 'obfusk/data/base'
12
+ require 'obfusk/data/valid'
13
13
 
14
14
  module Obfusk
15
15
  module Data
16
16
 
17
17
  # @todo document
18
- class ValidHash < Hash # {{{1
18
+ # @todo what to do about defaults !?
19
+ class ValidHashBase < Hash # {{{1
19
20
 
20
- include Base
21
+ include Valid
21
22
 
22
- class InvalidError < RuntimeError; end
23
+ TRANSFORMATIONS = %w{
24
+ []= clear delete merge! replace shift store update
25
+ }.map(&:to_sym)
23
26
 
24
- %w{
25
- []= clear delete delete_if keep_if merge! reject! replace
26
- select! shift store update
27
- }.map(&:to_sym).each do |m|
27
+ TRANSFORMATIONS_ENUMERATORS = %w{
28
+ delete_if keep_if reject! select!
29
+ }.map(&:to_sym)
30
+
31
+ UNIMPLEMENTED = %w{
32
+ compare_by_identity default= default_proc=
33
+ }.map(&:to_sym)
34
+
35
+ UNIMPLEMENTED.each do |m|
28
36
  define_method m do |*a, &b|
29
- r = super(*a, &b); validate!; r
37
+ raise NotImplementedError
30
38
  end
31
39
  end
32
40
 
33
41
  def self.[] (*a, &b)
34
- x = super; x.validate!; x
35
- end
36
-
37
- def initialize (data = {}, &block)
38
- super(&block); self.merge! data
42
+ # NB: we must validate b/c super uses allocate instead of new
43
+ super.validate!
39
44
  end
40
45
 
41
- def compare_by_identity
42
- raise NotImplementedError
46
+ def initialize (data = {}, &b)
47
+ super(&b); self.merge! data
43
48
  end
44
49
 
50
+ # @return [Hash]
45
51
  def invert
46
52
  Hash[self].invert
47
53
  end
48
54
 
49
55
  def merge (*a, &b)
50
- x = super; x.validate!; x
56
+ super.validate!
51
57
  end
52
58
 
53
59
  def reject (*a, &b)
54
- x = super; x.validate!; x
60
+ return to_enum :reject, *a unless b
61
+ super.validate!
55
62
  end
56
63
 
57
64
  def select (*a, &b)
58
- x = self.class[super]; x.validate!; x # TODO
65
+ return to_enum :select, *a unless b
66
+
67
+ # NB: super returns a Hash; implementing select manually is
68
+ # problematic b/c new() and []=; this is the simplest (but not
69
+ # the most efficient -- b/c copying) implementation
70
+
71
+ self.class[super] # TODO
59
72
  end
60
73
 
74
+ # @return [Hash]
61
75
  def to_hash
62
76
  Hash[self]
63
77
  end
64
78
 
65
79
  end # }}}1
66
80
 
81
+ # @todo document
82
+ class ValidHash < ValidHashBase # {{{1
83
+
84
+ alias_method :__validhash__original_replace__, :replace
85
+ private :__validhash__original_replace__
86
+
87
+ def __validhash__validate_and_rollback__ (c, r)
88
+ begin
89
+ validate!; r
90
+ rescue InvalidError
91
+ __validhash__original_replace__ c; raise
92
+ end
93
+ end
94
+ private :__validhash__validate_and_rollback__
95
+
96
+ TRANSFORMATIONS.each do |m|
97
+ define_method m do |*a, &b|
98
+ __validhash__validate_and_rollback__ dup, super(*a, &b)
99
+ end
100
+ end
101
+
102
+ TRANSFORMATIONS_ENUMERATORS.each do |m|
103
+ define_method m do |*a, &b|
104
+ return to_enum m, *a unless b
105
+ __validhash__validate_and_rollback__ dup, super(*a, &b)
106
+ end
107
+ end
108
+
109
+ end # }}}1
110
+
111
+ # @todo document
112
+ class UnsafeValidHash < ValidHashBase # {{{1
113
+
114
+ TRANSFORMATIONS.each do |m|
115
+ define_method m do |*a, &b|
116
+ r = super(*a, &b); validate!; r
117
+ end
118
+ end
119
+
120
+ TRANSFORMATIONS_ENUMERATORS.each do |m|
121
+ define_method m do |*a, &b|
122
+ return to_enum m, *a unless b
123
+ r = super(*a, &b); validate!; r
124
+ end
125
+ end
126
+
127
+ end # }}}1
128
+
67
129
  end
68
130
  end
69
131
 
@@ -1,8 +1,8 @@
1
1
  # -- ; {{{1
2
2
  #
3
- # File : obfusk/data/base.rb
3
+ # File : obfusk/data/valid.rb
4
4
  # Maintainer : Felix C. Stegerman <flx@obfusk.net>
5
- # Date : 2013-02-11
5
+ # Date : 2013-02-13
6
6
  #
7
7
  # Copyright : Copyright (C) 2013 Felix C. Stegerman
8
8
  # Licence : GPLv2 or EPLv1
@@ -14,7 +14,10 @@ require 'obfusk/data'
14
14
  module Obfusk
15
15
  module Data
16
16
 
17
- module Base
17
+ # @todo document
18
+ module Valid
19
+
20
+ class InvalidError < RuntimeError; end
18
21
 
19
22
  def self.included (base)
20
23
  base.extend ClassMethods
@@ -35,6 +38,7 @@ module Obfusk
35
38
  def validate!
36
39
  e = Obfusk::Data.validate self.class::VALIDATOR, self
37
40
  raise self.class::InvalidError, e.join('; ') if e
41
+ self
38
42
  end
39
43
 
40
44
  def valid?
@@ -1,6 +1,6 @@
1
1
  module Obfusk
2
2
  module Data
3
- VERSION = '0.0.2.SNAPSHOT.20130212031255'
3
+ VERSION = '0.0.2.SNAPSHOT.20130213231507'
4
4
  DATE = '2013-02-11'
5
5
  end
6
6
  end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # File : obfusk/data/hamster_spec.rb
4
4
  # Maintainer : Felix C. Stegerman <flx@obfusk.net>
5
- # Date : 2013-02-11
5
+ # Date : 2013-02-13
6
6
  #
7
7
  # Copyright : Copyright (C) 2013 Felix C. Stegerman
8
8
  # Licence : GPLv2 or EPLv1
@@ -26,7 +26,7 @@ module Obfusk::Data::Hamster__Spec
26
26
  end
27
27
  end
28
28
 
29
- E = Obfusk::Data::ValidHamster::InvalidError
29
+ E = Obfusk::Data::Valid::InvalidError
30
30
 
31
31
  # --
32
32
 
@@ -43,15 +43,15 @@ module Obfusk::Data::Hamster__Spec
43
43
  Bar.new some_other_field: 37
44
44
  end
45
45
  it 'invalid Bar' do
46
- expect { Bar.new baz: 42 }.to raise_error E
46
+ expect { Bar.new baz: 42 }.to raise_error(E)
47
47
  end
48
48
  it 'invalid Bar merge' do
49
49
  b = Bar.new
50
- expect { b.merge Hamster.hash baz: 42 }.to raise_error E
50
+ expect { b.merge Hamster.hash baz: 42 }.to raise_error(E)
51
51
  end
52
52
  it 'invalid Bar put' do
53
53
  b = Bar.new
54
- expect { b.put :bar, 'hi!' }.to raise_error E
54
+ expect { b.put :bar, 'hi!' }.to raise_error(E)
55
55
  end
56
56
  end # }}}1
57
57
 
@@ -64,14 +64,14 @@ module Obfusk::Data::Hamster__Spec
64
64
  b.except :maybe
65
65
  end
66
66
  it 'invalid empty Baz (new)' do
67
- expect { Baz.new }.to raise_error E
67
+ expect { Baz.new }.to raise_error(E)
68
68
  end
69
69
  it 'invalid empty Baz (empty)' do
70
- expect { Baz.empty }.to raise_error E
70
+ expect { Baz.empty }.to raise_error(E)
71
71
  end
72
72
  it 'invalid Baz except' do
73
73
  b = Baz.new baz: 1, maybe: 2
74
- expect { b.except :baz }.to raise_error E
74
+ expect { b.except :baz }.to raise_error(E)
75
75
  end
76
76
  end # }}}1
77
77
 
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # File : obfusk/data/hash_spec.rb
4
4
  # Maintainer : Felix C. Stegerman <flx@obfusk.net>
5
- # Date : 2013-02-11
5
+ # Date : 2013-02-13
6
6
  #
7
7
  # Copyright : Copyright (C) 2013 Felix C. Stegerman
8
8
  # Licence : GPLv2 or EPLv1
@@ -20,12 +20,14 @@ module Obfusk::Data::Hash__Spec
20
20
  end
21
21
 
22
22
  class Baz < Obfusk::Data::ValidHash
23
- data do
24
- field :baz, []
25
- end
23
+ data { field :baz, [] }
24
+ end
25
+
26
+ class Qux < Obfusk::Data::UnsafeValidHash
27
+ data { field :qux, [] }
26
28
  end
27
29
 
28
- E = Obfusk::Data::ValidHash::InvalidError
30
+ E = Obfusk::Data::Valid::InvalidError
29
31
 
30
32
  # --
31
33
 
@@ -42,22 +44,42 @@ module Obfusk::Data::Hash__Spec
42
44
  Bar.new some_other_field: 37
43
45
  end
44
46
  it 'invalid Bar' do
45
- expect { Bar.new baz: 42 }.to raise_error E
47
+ expect { Bar.new baz: 42 }.to raise_error(E)
46
48
  end
47
49
  it 'invalid Bar merge' do
48
50
  b = Bar.new
49
- expect { b.merge baz: 42 }.to raise_error E
51
+ expect { b.merge baz: 42 }.to raise_error(E)
52
+ b.should be_valid
50
53
  end
51
54
  it 'invalid Bar []=' do
52
55
  b = Bar.new
53
- expect { b[:bar] = 'hi!' }.to raise_error E
56
+ expect { b[:bar] = 'hi!' }.to raise_error(E)
57
+ b.should be_valid
54
58
  end
55
59
  end # }}}1
56
60
 
57
61
  context 'Baz' do # {{{1
58
62
  it 'invalid Baz clear' do
59
63
  b = Baz.new baz: 'ok'
60
- expect { b.clear }.to raise_error E
64
+ expect { b.clear }.to raise_error(E)
65
+ b.should be_valid
66
+ end
67
+ it 'invalid Baz reject!' do
68
+ b = Baz.new baz: 'ok'
69
+ f = b.reject!
70
+ expect { f.each { true } }.to raise_error(E)
71
+ b[:baz].should == 'ok'
72
+ b.should be_valid
73
+ end
74
+ end # }}}1
75
+
76
+ context 'Qux' do # {{{1
77
+ it 'invalid Qux reject!' do
78
+ q = Qux.new qux: 'ok'
79
+ f = q.reject!
80
+ expect { f.each { true } }.to raise_error(E)
81
+ q.should be_empty
82
+ q.should_not be_valid
61
83
  end
62
84
  end # }}}1
63
85
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obfusk-data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2.SNAPSHOT.20130212031255
4
+ version: 0.0.2.SNAPSHOT.20130213231507
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2013-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hamster
16
- requirement: &20985220 !ruby/object:Gem::Requirement
16
+ requirement: &19084200 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *20985220
24
+ version_requirements: *19084200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &20928520 !ruby/object:Gem::Requirement
27
+ requirement: &19083580 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *20928520
35
+ version_requirements: *19083580
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &20927780 !ruby/object:Gem::Requirement
38
+ requirement: &19082880 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *20927780
46
+ version_requirements: *19082880
47
47
  description: ! '...
48
48
 
49
49
  '
@@ -59,7 +59,7 @@ files:
59
59
  - lib/obfusk/data/hamster.rb
60
60
  - lib/obfusk/data/version.rb
61
61
  - lib/obfusk/data/hash.rb
62
- - lib/obfusk/data/base.rb
62
+ - lib/obfusk/data/valid.rb
63
63
  - lib/obfusk/data.rb
64
64
  - spec/_data.rb
65
65
  - spec/obfusk/data/hash_spec.rb