structural 0.0.3 → 0.1.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.
- checksums.yaml +7 -0
- data/lib/structural/hashifier.rb +6 -15
- data/lib/structural/model.rb +3 -3
- data/lib/structural/model/definer.rb +6 -6
- data/lib/structural/model/field.rb +9 -5
- data/lib/structural/model/type_casts.rb +19 -38
- data/lib/structural/timestamps.rb +1 -1
- data/lib/structural/version.rb +1 -1
- data/spec/lib/structural/model/type_casts_spec.rb +6 -22
- data/spec/lib/structural/model_spec.rb +6 -0
- metadata +104 -127
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d2e683ae4dc0a1839b52352576db3fc726201321
|
4
|
+
data.tar.gz: 947df1932b578c7c5e786b2e6baf4463f2d10312
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c4da802d16a95c7d4b5516697fb9c6c76687032686e693830c6c3f8b44a3aa47c3f9adb3ca9341ccf378afafb0e75b118ac186ed612d9ab7fa274efefffcd4a7
|
7
|
+
data.tar.gz: a1f58451da825b7bc071958150407011f743d2ab4411692095b6197a0a3377a749ca6de810170b1098dfa525457e00ff83e398ece251d3d2d7b1088e9dbc5e26
|
data/lib/structural/hashifier.rb
CHANGED
@@ -1,27 +1,18 @@
|
|
1
1
|
module Structural
|
2
2
|
class Hashifier
|
3
3
|
def self.hashify(data)
|
4
|
-
|
4
|
+
{}.tap do |hash|
|
5
|
+
data.each do |key, value|
|
6
|
+
hash[key.to_sym] = as_data(value)
|
7
|
+
end
|
8
|
+
end
|
5
9
|
end
|
6
10
|
|
7
|
-
def
|
8
|
-
@data = data
|
9
|
-
end
|
10
|
-
|
11
|
-
def hashify
|
12
|
-
Hash[data.map { |k, v| [ k.to_s, as_data(v) ] }]
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def as_data(v)
|
11
|
+
def self.as_data(v)
|
18
12
|
case v
|
19
13
|
when Structural::Model then v.data
|
20
14
|
when Array then v.first.is_a?(Structural::Model) ? v.map(&:data) : v
|
21
|
-
when Hash then Hashifier.hashify(v)
|
22
15
|
else v end
|
23
16
|
end
|
24
|
-
|
25
|
-
attr_reader :data
|
26
17
|
end
|
27
18
|
end
|
data/lib/structural/model.rb
CHANGED
@@ -11,7 +11,7 @@ module Structural
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def unset(*keys)
|
14
|
-
self.class.new(data.except(*keys.map(&:
|
14
|
+
self.class.new(data.except(*keys.map(&:to_sym)))
|
15
15
|
end
|
16
16
|
|
17
17
|
def eql? other
|
@@ -29,8 +29,8 @@ module Structural
|
|
29
29
|
base.extend(Descriptor)
|
30
30
|
end
|
31
31
|
|
32
|
-
def memoize(
|
33
|
-
instance_variable_get(
|
32
|
+
def memoize(ivar, &b)
|
33
|
+
instance_variable_get(ivar) || instance_variable_set(ivar, b.call(data))
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
module Structural
|
2
2
|
module Model
|
3
3
|
class Definer
|
4
|
-
def self.method_memoize(context, name, &value_block)
|
5
|
-
|
6
|
-
|
7
|
-
memoize(
|
4
|
+
def self.method_memoize(context, name, ivar_name, &value_block)
|
5
|
+
context.class_eval do
|
6
|
+
define_method(name) do
|
7
|
+
memoize(ivar_name, &value_block)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.method(context, name, &value_block)
|
13
|
-
context.
|
14
|
-
define_method
|
13
|
+
context.class_eval do
|
14
|
+
define_method(name) do
|
15
15
|
value_block.call(self)
|
16
16
|
end
|
17
17
|
end
|
@@ -8,7 +8,7 @@ module Structural
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def define
|
11
|
-
Definer.method_memoize(model, name) { |data| value_of(data) }
|
11
|
+
Definer.method_memoize(model, name, ivar_name) { |data| value_of(data) }
|
12
12
|
Definer.method(model, "#{name}?") { |obj| presence_of(obj.data) }
|
13
13
|
hook_define
|
14
14
|
end
|
@@ -26,18 +26,22 @@ module Structural
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def cast(value)
|
29
|
-
TypeCasts.cast(options.fetch(:type,
|
29
|
+
TypeCasts.cast(options.fetch(:type, value.class), value)
|
30
30
|
end
|
31
31
|
|
32
32
|
def key
|
33
|
-
options.fetch(:key, name).
|
33
|
+
options.fetch(:key, name).to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
def ivar_name
|
37
|
+
@ivar_name ||= "@#{@name}"
|
34
38
|
end
|
35
39
|
|
36
40
|
def default_value
|
37
|
-
proc do
|
41
|
+
@default_value ||= proc do
|
38
42
|
if default?
|
39
43
|
default
|
40
|
-
else
|
44
|
+
else
|
41
45
|
raise MissingAttributeError, key
|
42
46
|
end
|
43
47
|
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
module Structural
|
2
2
|
module Model
|
3
3
|
module TypeCasts
|
4
|
+
|
4
5
|
def self.cast(type, value)
|
5
|
-
|
6
|
+
if value.is_a?(type)
|
7
|
+
value
|
8
|
+
else
|
9
|
+
casts.fetch(type, Identity).cast(value)
|
10
|
+
end
|
6
11
|
end
|
7
12
|
|
8
|
-
protected
|
9
|
-
|
10
13
|
def self.register(cast)
|
11
14
|
casts[cast.type] = cast
|
12
15
|
end
|
@@ -17,92 +20,70 @@ module Structural
|
|
17
20
|
@casts ||= {}
|
18
21
|
end
|
19
22
|
|
20
|
-
class
|
21
|
-
def initialize(value)
|
22
|
-
@value = value
|
23
|
-
end
|
24
|
-
|
25
|
-
def cast
|
26
|
-
value.is_a?(type) ? value : conversion
|
27
|
-
end
|
28
|
-
|
29
|
-
def type
|
30
|
-
self.class.type
|
31
|
-
end
|
32
|
-
|
33
|
-
def conversion
|
34
|
-
raise NotImplementedError
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
23
|
+
class Identity
|
39
24
|
def self.type
|
40
|
-
|
25
|
+
::Identity
|
41
26
|
end
|
42
27
|
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
class Identity < Cast
|
47
|
-
def cast
|
28
|
+
def self.cast(value)
|
48
29
|
value
|
49
30
|
end
|
50
31
|
end
|
51
32
|
|
52
|
-
class Integer
|
33
|
+
class Integer
|
53
34
|
def self.type
|
54
35
|
::Integer
|
55
36
|
end
|
56
37
|
|
57
|
-
def
|
38
|
+
def self.cast(value)
|
58
39
|
value.to_i
|
59
40
|
end
|
60
41
|
|
61
42
|
TypeCasts.register(self)
|
62
43
|
end
|
63
44
|
|
64
|
-
class Float
|
45
|
+
class Float
|
65
46
|
def self.type
|
66
47
|
::Float
|
67
48
|
end
|
68
49
|
|
69
|
-
def
|
50
|
+
def self.cast(value)
|
70
51
|
value.to_f
|
71
52
|
end
|
72
53
|
|
73
54
|
TypeCasts.register(self)
|
74
55
|
end
|
75
56
|
|
76
|
-
class Date
|
57
|
+
class Date
|
77
58
|
def self.type
|
78
59
|
::Date
|
79
60
|
end
|
80
61
|
|
81
|
-
def
|
62
|
+
def self.cast(value)
|
82
63
|
::Date.parse value
|
83
64
|
end
|
84
65
|
|
85
66
|
TypeCasts.register(self)
|
86
67
|
end
|
87
68
|
|
88
|
-
class Time
|
69
|
+
class Time
|
89
70
|
def self.type
|
90
71
|
::Time
|
91
72
|
end
|
92
73
|
|
93
|
-
def
|
74
|
+
def self.cast(value)
|
94
75
|
::Time.parse value
|
95
76
|
end
|
96
77
|
|
97
78
|
TypeCasts.register(self)
|
98
79
|
end
|
99
80
|
|
100
|
-
class Money
|
81
|
+
class Money
|
101
82
|
def self.type
|
102
83
|
::Money
|
103
84
|
end
|
104
85
|
|
105
|
-
def
|
86
|
+
def self.cast(value)
|
106
87
|
::Money.new value.to_i
|
107
88
|
end
|
108
89
|
|
data/lib/structural/version.rb
CHANGED
@@ -3,19 +3,8 @@ require 'spec_helper'
|
|
3
3
|
module Structural
|
4
4
|
module Model
|
5
5
|
module TypeCasts
|
6
|
-
describe Cast do
|
7
|
-
it 'requires a type' do
|
8
|
-
expect { Cast.new(1).type }.to raise_error NotImplementedError
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'requires a conversion' do
|
12
|
-
expect { Cast.new(1).conversion }.to raise_error NotImplementedError
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
6
|
describe Integer do
|
18
|
-
subject { Integer.
|
7
|
+
subject { Integer.cast("2") }
|
19
8
|
|
20
9
|
it 'casts strings to integers' do
|
21
10
|
expect(subject).to eql(2)
|
@@ -23,7 +12,7 @@ module Structural
|
|
23
12
|
end
|
24
13
|
|
25
14
|
describe Float do
|
26
|
-
subject { Float.
|
15
|
+
subject { Float.cast("2.0") }
|
27
16
|
|
28
17
|
it 'casts strings to floats' do
|
29
18
|
expect(subject).to eql(2.0)
|
@@ -32,25 +21,20 @@ module Structural
|
|
32
21
|
|
33
22
|
describe Date do
|
34
23
|
it 'casts strings to dates' do
|
35
|
-
Date.
|
24
|
+
Date.cast("06-06-1983").should eq ::Date.new(1983, 6, 6)
|
36
25
|
end
|
37
26
|
end
|
38
27
|
|
39
28
|
describe Time do
|
40
29
|
it 'casts strings to Times' do
|
41
|
-
Time.
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'does nothing if the value is already of the correct type' do
|
45
|
-
time = ::Time.now
|
46
|
-
Time.new(time).cast.should eq time
|
30
|
+
Time.cast("06-06-1983").should eq ::Time.parse("06-06-1983")
|
47
31
|
end
|
48
32
|
end
|
49
33
|
|
50
34
|
describe Money do
|
51
35
|
it 'ints or strings to Money' do
|
52
|
-
Money.
|
53
|
-
Money.
|
36
|
+
Money.cast("500").should eq ::Money.new(5_00)
|
37
|
+
Money.cast(500).should eq ::Money.new(5_00)
|
54
38
|
end
|
55
39
|
end
|
56
40
|
end
|
@@ -10,6 +10,7 @@ class TestModel
|
|
10
10
|
|
11
11
|
field :foo
|
12
12
|
field :bar, :key => 'baz'
|
13
|
+
field :nested_hash
|
13
14
|
field :quux, :default => false
|
14
15
|
field :date_of_birth, :type => Date
|
15
16
|
field :empty_date, :type => Date
|
@@ -33,6 +34,7 @@ describe Structural::Model do
|
|
33
34
|
:foo => 3,
|
34
35
|
:baz => 6,
|
35
36
|
:quxx => 8,
|
37
|
+
:nested_hash => {1 => :one, 2 => :two},
|
36
38
|
:test_model => {},
|
37
39
|
:date_of_birth => '06-06-1983',
|
38
40
|
:aliased_model => {'yak' => 11},
|
@@ -62,6 +64,10 @@ describe Structural::Model do
|
|
62
64
|
model.quux.should eql(false)
|
63
65
|
end
|
64
66
|
|
67
|
+
it 'leaves nested hashes unmodified' do
|
68
|
+
model.nested_hash.should eql({1 => :one, 2 => :two})
|
69
|
+
end
|
70
|
+
|
65
71
|
describe "typecast option" do
|
66
72
|
it 'typecasts to the provided type if a cast exists' do
|
67
73
|
model.date_of_birth.should be_a Date
|
metadata
CHANGED
@@ -1,138 +1,125 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: structural
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease: false
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 3
|
10
|
-
version: 0.0.3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Russell Dunphy
|
14
8
|
- Radek Molenda
|
15
9
|
- Jon Doveston
|
16
10
|
autorequire:
|
17
11
|
bindir: bin
|
18
12
|
cert_chain: []
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
dependencies:
|
23
|
-
- !ruby/object:Gem::Dependency
|
13
|
+
date: 2016-11-07 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
24
16
|
name: money
|
25
|
-
|
26
|
-
|
27
|
-
none: false
|
28
|
-
requirements:
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
29
19
|
- - ">="
|
30
|
-
- !ruby/object:Gem::Version
|
31
|
-
|
32
|
-
segments:
|
33
|
-
- 0
|
34
|
-
version: "0"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
35
22
|
type: :runtime
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: activesupport
|
39
23
|
prerelease: false
|
40
|
-
|
41
|
-
|
42
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: activesupport
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
43
33
|
- - ">="
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
segments:
|
47
|
-
- 0
|
48
|
-
version: "0"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
49
36
|
type: :runtime
|
50
|
-
version_requirements: *id002
|
51
|
-
- !ruby/object:Gem::Dependency
|
52
|
-
name: rspec
|
53
37
|
prerelease: false
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rspec
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '3.0'
|
64
50
|
type: :development
|
65
|
-
version_requirements: *id003
|
66
|
-
- !ruby/object:Gem::Dependency
|
67
|
-
name: yard
|
68
51
|
prerelease: false
|
69
|
-
|
70
|
-
|
71
|
-
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '3.0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: yard
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
72
61
|
- - ">="
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
|
75
|
-
segments:
|
76
|
-
- 0
|
77
|
-
version: "0"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
78
64
|
type: :development
|
79
|
-
version_requirements: *id004
|
80
|
-
- !ruby/object:Gem::Dependency
|
81
|
-
name: redcarpet
|
82
65
|
prerelease: false
|
83
|
-
|
84
|
-
|
85
|
-
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: redcarpet
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
86
75
|
- - ">="
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
|
89
|
-
segments:
|
90
|
-
- 0
|
91
|
-
version: "0"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
92
78
|
type: :development
|
93
|
-
version_requirements: *id005
|
94
|
-
- !ruby/object:Gem::Dependency
|
95
|
-
name: bundler
|
96
79
|
prerelease: false
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: bundler
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '1.6'
|
107
92
|
type: :development
|
108
|
-
version_requirements: *id006
|
109
|
-
- !ruby/object:Gem::Dependency
|
110
|
-
name: rake
|
111
93
|
prerelease: false
|
112
|
-
|
113
|
-
|
114
|
-
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '1.6'
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: rake
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
115
103
|
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
|
118
|
-
segments:
|
119
|
-
- 0
|
120
|
-
version: "0"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
121
106
|
type: :development
|
122
|
-
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
123
113
|
description: A cut down fork of the Id gem developed at On The Beach Ltd.
|
124
|
-
email:
|
114
|
+
email:
|
125
115
|
- jon.doveston@onthebeach.co.uk
|
126
116
|
executables: []
|
127
|
-
|
128
117
|
extensions: []
|
129
|
-
|
130
118
|
extra_rdoc_files: []
|
131
|
-
|
132
|
-
|
133
|
-
- .
|
134
|
-
- .
|
135
|
-
- .travis.yml
|
119
|
+
files:
|
120
|
+
- ".gitignore"
|
121
|
+
- ".ruby-version"
|
122
|
+
- ".travis.yml"
|
136
123
|
- CONTRIBUTING.md
|
137
124
|
- Gemfile
|
138
125
|
- LICENSE.md
|
@@ -158,41 +145,31 @@ files:
|
|
158
145
|
- spec/lib/structural/timestamps_spec.rb
|
159
146
|
- spec/spec_helper.rb
|
160
147
|
- structural.gemspec
|
161
|
-
has_rdoc: true
|
162
148
|
homepage: https://github.com/onthebeach/structural
|
163
|
-
licenses:
|
149
|
+
licenses:
|
164
150
|
- MIT
|
151
|
+
metadata: {}
|
165
152
|
post_install_message:
|
166
153
|
rdoc_options: []
|
167
|
-
|
168
|
-
require_paths:
|
154
|
+
require_paths:
|
169
155
|
- lib
|
170
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
-
|
172
|
-
requirements:
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
173
158
|
- - ">="
|
174
|
-
- !ruby/object:Gem::Version
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
version: "0"
|
179
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
|
-
none: false
|
181
|
-
requirements:
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
182
163
|
- - ">="
|
183
|
-
- !ruby/object:Gem::Version
|
184
|
-
|
185
|
-
segments:
|
186
|
-
- 0
|
187
|
-
version: "0"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
188
166
|
requirements: []
|
189
|
-
|
190
167
|
rubyforge_project:
|
191
|
-
rubygems_version:
|
168
|
+
rubygems_version: 2.5.1
|
192
169
|
signing_key:
|
193
|
-
specification_version:
|
170
|
+
specification_version: 4
|
194
171
|
summary: Simple models based on hashes
|
195
|
-
test_files:
|
172
|
+
test_files:
|
196
173
|
- spec/lib/structural/model/association_spec.rb
|
197
174
|
- spec/lib/structural/model/field_spec.rb
|
198
175
|
- spec/lib/structural/model/type_casts_spec.rb
|