chione 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -1
- data.tar.gz.sig +0 -0
- data/History.md +8 -0
- data/Rakefile +2 -3
- data/lib/chione.rb +1 -1
- data/lib/chione/component.rb +38 -22
- data/lib/chione/mixins.rb +87 -0
- data/spec/chione/component_spec.rb +16 -1
- data/spec/chione/mixins_spec.rb +126 -0
- metadata +14 -8
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 499f4f5ac15a4abdc2e443cc3cb89c0961be6fecb97251e014199cfb0ba82dde
|
4
|
+
data.tar.gz: f0cc3da0ebcb1a8aea02cf10dac2eeb7bd26986df587db3a39238bbff69133a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfeda410c67704987bc1b049f9fe2b2521bfce8411d4360d878db767883590b874e165e6c965b68f1181d82fde2305fe36a93fb3d7d9941a2f8b477c97950132
|
7
|
+
data.tar.gz: eeddaa0889e2e6dc59f7c8f9e217a8c6a72902449bab6e7f397b232dfb4da114b07873b1fa6d9a991abecd118ad1403be203983e6c96922d30d9afe7dd666b53
|
checksums.yaml.gz.sig
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
��G&/�9�Cߎ�D�h�צ���`>3�����|SRF�s���,꺅�1���0-���D�ϳ�4tu�߲��[6���0?T3����q.��)�}AwQK[��cs��C!�d\�,�A7�����a�X��m��Z'����e�Z���Y��<�O�.���+�@&"Ɏ5d��� ��)��|7�O�}����9���J?��Y��&�W{z�u�y�)e�2X���z��3��2,N?y=N=+5q흵q�s� %��:�8U�z��-�J�= B��uDkiݴ�Ȉo^c>�X(� (��!N�cO�Y�b��Y��_�"-�һ�!H]��?U~��Z�Z��익h�犦��H��(+U�8�{%��Y,^&��
|
data.tar.gz.sig
CHANGED
Binary file
|
data/History.md
CHANGED
data/Rakefile
CHANGED
@@ -39,10 +39,9 @@ hoespec = Hoe.spec 'chione' do |spec|
|
|
39
39
|
spec.dependency 'fluent_fixtures', '~> 0.6'
|
40
40
|
spec.dependency 'faker', '~> 1.8'
|
41
41
|
|
42
|
-
spec.dependency 'hoe-deveiate', '~>
|
42
|
+
spec.dependency 'hoe-deveiate', '~> 0.10', :developer
|
43
43
|
spec.dependency 'simplecov', '~> 0.12', :developer
|
44
|
-
spec.dependency 'rdoc-generator-fivefish', '~> 0.
|
45
|
-
spec.dependency 'rdoc', '~> 5.1', :developer
|
44
|
+
spec.dependency 'rdoc-generator-fivefish', '~> 0.4', :developer
|
46
45
|
|
47
46
|
spec.require_ruby_version( '>=2.5.0' )
|
48
47
|
spec.hg_sign_tags = true if spec.respond_to?( :hg_sign_tags= )
|
data/lib/chione.rb
CHANGED
data/lib/chione/component.rb
CHANGED
@@ -32,17 +32,46 @@ class Chione::Component
|
|
32
32
|
### +default+. If the optional +process_block+ is provided, it will be called
|
33
33
|
### with the new value being assigned to the field before it is set, and the
|
34
34
|
### return value of it will be used instead.
|
35
|
-
def self::field( name,
|
35
|
+
def self::field( name, **options, &process_block )
|
36
|
+
options[ :processor ] = process_block
|
36
37
|
self.fields ||= {}
|
37
|
-
self.fields[ name ] =
|
38
|
+
self.fields[ name ] = options
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
# Add some class method
|
41
|
+
self.define_singleton_method( "processor_for_#{name}" ) do
|
42
|
+
return self.fields.dig( name, :processor )
|
43
|
+
end
|
44
|
+
self.define_singleton_method( "default_for_#{name}" ) do
|
45
|
+
default = self.fields.dig( name, :default )
|
46
|
+
return default.call( self ) if default.respond_to?( :call )
|
47
|
+
return Chione::DataUtilities.deep_copy( default )
|
48
|
+
end
|
49
|
+
self.define_singleton_method( "options_for_#{name}" ) do
|
50
|
+
return self.fields[ name ]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Add instance methods as a mixin so they can be overridden and super()ed to
|
54
|
+
mixin = self.make_field_mixin( name )
|
55
|
+
self.include( mixin )
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
### Make a mixin module with methods for the field with the specified +name+.
|
61
|
+
def self::make_field_mixin( name )
|
62
|
+
mixin = Module.new
|
63
|
+
|
64
|
+
mixin.attr_reader( name )
|
65
|
+
mixin.define_method( "process_#{name}" ) do |value|
|
66
|
+
processor = self.class.send( "processor_for_#{name}" ) or return value
|
67
|
+
return processor.call( value )
|
68
|
+
end
|
69
|
+
mixin.define_method( "#{name}=" ) do |new_val|
|
70
|
+
new_val = self.send( "process_#{name}", new_val )
|
42
71
|
self.instance_variable_set( "@#{name}", new_val )
|
43
72
|
end
|
44
73
|
|
45
|
-
|
74
|
+
return mixin
|
46
75
|
end
|
47
76
|
|
48
77
|
|
@@ -56,8 +85,9 @@ class Chione::Component
|
|
56
85
|
@entity_id = entity_id
|
57
86
|
|
58
87
|
if self.class.fields
|
59
|
-
self.class.fields.
|
60
|
-
|
88
|
+
self.class.fields.each_key do |name|
|
89
|
+
val = values[ name ] || self.class.send( "default_for_#{name}" )
|
90
|
+
self.public_send( "#{name}=", val )
|
61
91
|
end
|
62
92
|
end
|
63
93
|
end
|
@@ -102,20 +132,6 @@ class Chione::Component
|
|
102
132
|
private
|
103
133
|
#######
|
104
134
|
|
105
|
-
### Process the given +default+ value so it's suitable for use as a default
|
106
|
-
### attribute value.
|
107
|
-
def default_value( default )
|
108
|
-
return default.call( self ) if default.respond_to?( :call )
|
109
|
-
return deep_copy( default )
|
110
|
-
end
|
111
|
-
|
112
|
-
|
113
|
-
### Make a deep copy of the specified +value+.
|
114
|
-
def deep_copy( value )
|
115
|
-
return Marshal.load( Marshal.dump(value) )
|
116
|
-
end
|
117
|
-
|
118
|
-
|
119
135
|
### Return a slice of the specified +string+ truncated to at most +maxlen+
|
120
136
|
### characters. Returns the unchanged +string+ if it's not longer than +maxlen+.
|
121
137
|
def truncate_string( string, maxlen )
|
data/lib/chione/mixins.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
#encoding: utf-8
|
3
3
|
|
4
|
+
require 'tempfile'
|
4
5
|
require 'chione' unless defined?( Chione )
|
5
6
|
|
6
7
|
|
@@ -110,4 +111,90 @@ module Chione
|
|
110
111
|
end # module Inspection
|
111
112
|
|
112
113
|
|
114
|
+
# A collection of miscellaneous functions that are useful for manipulating
|
115
|
+
# complex data structures.
|
116
|
+
#
|
117
|
+
# include Chione::DataUtilities
|
118
|
+
# newhash = deep_copy( oldhash )
|
119
|
+
#
|
120
|
+
module DataUtilities
|
121
|
+
|
122
|
+
###############
|
123
|
+
module_function
|
124
|
+
###############
|
125
|
+
|
126
|
+
### Recursively copy the specified +obj+ and return the result.
|
127
|
+
def deep_copy( obj )
|
128
|
+
|
129
|
+
# Handle mocks during testing
|
130
|
+
return obj if obj.class.name == 'RSpec::Mocks::Mock'
|
131
|
+
|
132
|
+
return case obj
|
133
|
+
when NilClass, Numeric, TrueClass, FalseClass, Symbol,
|
134
|
+
Module, Encoding, IO, Tempfile
|
135
|
+
obj
|
136
|
+
|
137
|
+
when Array
|
138
|
+
obj.map {|o| deep_copy(o) }
|
139
|
+
|
140
|
+
when Hash
|
141
|
+
newhash = {}
|
142
|
+
newhash.default_proc = obj.default_proc if obj.default_proc
|
143
|
+
obj.each do |k,v|
|
144
|
+
newhash[ deep_copy(k) ] = deep_copy( v )
|
145
|
+
end
|
146
|
+
newhash
|
147
|
+
|
148
|
+
else
|
149
|
+
obj.clone
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
### Create and return a Hash that will auto-vivify any values it is missing with
|
155
|
+
### another auto-vivifying Hash.
|
156
|
+
def autovivify( hash, key )
|
157
|
+
hash[ key ] = Hash.new( &Chione::DataUtilities.method(:autovivify) )
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
### Return a version of the given +hash+ with its keys transformed
|
162
|
+
### into Strings from whatever they were before.
|
163
|
+
def stringify_keys( hash )
|
164
|
+
newhash = {}
|
165
|
+
|
166
|
+
hash.each do |key,val|
|
167
|
+
if val.is_a?( Hash )
|
168
|
+
newhash[ key.to_s ] = stringify_keys( val )
|
169
|
+
else
|
170
|
+
newhash[ key.to_s ] = val
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
return newhash
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
### Return a duplicate of the given +hash+ with its identifier-like keys
|
179
|
+
### transformed into symbols from whatever they were before.
|
180
|
+
def symbolify_keys( hash )
|
181
|
+
newhash = {}
|
182
|
+
|
183
|
+
hash.each do |key,val|
|
184
|
+
keysym = key.to_s.dup.untaint.to_sym
|
185
|
+
|
186
|
+
if val.is_a?( Hash )
|
187
|
+
newhash[ keysym ] = symbolify_keys( val )
|
188
|
+
else
|
189
|
+
newhash[ keysym ] = val
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
return newhash
|
194
|
+
end
|
195
|
+
alias_method :internify_keys, :symbolify_keys
|
196
|
+
|
197
|
+
end # module DataUtilities
|
198
|
+
|
199
|
+
|
113
200
|
end # module Chione
|
@@ -45,6 +45,9 @@ describe Chione::Component do
|
|
45
45
|
component_subclass.field( :x, default: 0 )
|
46
46
|
component_subclass.field( :y, default: 18 )
|
47
47
|
|
48
|
+
expect( component_subclass.default_for_x ).to eq( 0 )
|
49
|
+
expect( component_subclass.default_for_y ).to eq( 18 )
|
50
|
+
|
48
51
|
instance = component_subclass.new
|
49
52
|
expect( instance.x ).to eq( 0 )
|
50
53
|
expect( instance.y ).to eq( 18 )
|
@@ -56,12 +59,22 @@ describe Chione::Component do
|
|
56
59
|
{ x: Integer(vals[0]), y: Integer(vals[1]) }
|
57
60
|
end
|
58
61
|
|
62
|
+
expect( component_subclass.processor_for_coordinates ).to respond_to( :call )
|
63
|
+
|
59
64
|
instance = component_subclass.new( coordinates: [88, 19] )
|
60
65
|
expect( instance.coordinates[:x] ).to eq( 88 )
|
61
66
|
expect( instance.coordinates[:y] ).to eq( 19 )
|
62
67
|
end
|
63
68
|
|
64
69
|
|
70
|
+
it "can declare a field with arbitrary options" do
|
71
|
+
component_subclass.field( :x, default: 1, serializable: false )
|
72
|
+
|
73
|
+
expect( component_subclass.options_for_x ).to include( serializable: false )
|
74
|
+
expect( component_subclass.default_for_x ).to eq( 1 )
|
75
|
+
end
|
76
|
+
|
77
|
+
|
65
78
|
it "uses a dup of the default if it's not an immediate object" do
|
66
79
|
component_subclass.field( :things, default: [] )
|
67
80
|
|
@@ -77,10 +90,12 @@ describe Chione::Component do
|
|
77
90
|
it "calls a callable default if it responds to #call" do
|
78
91
|
component_subclass.field( :oid, default: ->(obj) { obj.object_id } )
|
79
92
|
|
93
|
+
expect( component_subclass.default_for_oid ).to eq( component_subclass.object_id )
|
94
|
+
|
80
95
|
instance1 = component_subclass.new
|
81
96
|
instance2 = component_subclass.new( oid: 121212 )
|
82
97
|
|
83
|
-
expect( instance1.oid ).to eq(
|
98
|
+
expect( instance1.oid ).to eq( component_subclass.object_id )
|
84
99
|
expect( instance2.oid ).to eq( 121212 )
|
85
100
|
end
|
86
101
|
|
data/spec/chione/mixins_spec.rb
CHANGED
@@ -90,5 +90,131 @@ describe Chione, "mixins" do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
|
93
|
+
describe Chione::DataUtilities do
|
94
|
+
|
95
|
+
it "doesn't try to dup immediate objects" do
|
96
|
+
expect( Chione::DataUtilities.deep_copy( nil ) ).to be( nil )
|
97
|
+
expect( Chione::DataUtilities.deep_copy( 112 ) ).to be( 112 )
|
98
|
+
expect( Chione::DataUtilities.deep_copy( true ) ).to be( true )
|
99
|
+
expect( Chione::DataUtilities.deep_copy( false ) ).to be( false )
|
100
|
+
expect( Chione::DataUtilities.deep_copy( :a_symbol ) ).to be( :a_symbol )
|
101
|
+
end
|
102
|
+
|
103
|
+
it "doesn't try to dup modules/classes" do
|
104
|
+
klass = Class.new
|
105
|
+
expect( Chione::DataUtilities.deep_copy( klass ) ).to be( klass )
|
106
|
+
end
|
107
|
+
|
108
|
+
it "doesn't try to dup IOs" do
|
109
|
+
data = [ $stdin ]
|
110
|
+
expect( Chione::DataUtilities.deep_copy( data[0] ) ).to be( $stdin )
|
111
|
+
end
|
112
|
+
|
113
|
+
it "doesn't try to dup Tempfiles" do
|
114
|
+
data = Tempfile.new( 'strelka_deepcopy.XXXXX' )
|
115
|
+
expect( Chione::DataUtilities.deep_copy( data ) ).to be( data )
|
116
|
+
end
|
117
|
+
|
118
|
+
it "makes distinct copies of arrays and their members" do
|
119
|
+
original = [ 'foom', Set.new([ 1,2 ]), :a_symbol ]
|
120
|
+
|
121
|
+
copy = Chione::DataUtilities.deep_copy( original )
|
122
|
+
|
123
|
+
expect( copy ).to eq( original )
|
124
|
+
expect( copy ).to_not be( original )
|
125
|
+
expect( copy[0] ).to eq( original[0] )
|
126
|
+
expect( copy[0] ).to_not be( original[0] )
|
127
|
+
expect( copy[1] ).to eq( original[1] )
|
128
|
+
expect( copy[1] ).to_not be( original[1] )
|
129
|
+
expect( copy[2] ).to eq( original[2] )
|
130
|
+
expect( copy[2] ).to be( original[2] ) # Immediate
|
131
|
+
end
|
132
|
+
|
133
|
+
it "makes recursive copies of deeply-nested Arrays" do
|
134
|
+
original = [ 1, [ 2, 3, [4], 5], 6, [7, [8, 9], 0] ]
|
135
|
+
|
136
|
+
copy = Chione::DataUtilities.deep_copy( original )
|
137
|
+
|
138
|
+
expect( copy ).to eq( original )
|
139
|
+
expect( copy ).to_not be( original )
|
140
|
+
expect( copy[1] ).to_not be( original[1] )
|
141
|
+
expect( copy[1][2] ).to_not be( original[1][2] )
|
142
|
+
expect( copy[3] ).to_not be( original[3] )
|
143
|
+
expect( copy[3][1] ).to_not be( original[3][1] )
|
144
|
+
end
|
145
|
+
|
146
|
+
it "makes distinct copies of Hashes and their members" do
|
147
|
+
original = {
|
148
|
+
:a => 1,
|
149
|
+
'b' => 2,
|
150
|
+
3 => 'c',
|
151
|
+
}
|
152
|
+
|
153
|
+
copy = Chione::DataUtilities.deep_copy( original )
|
154
|
+
|
155
|
+
expect( copy ).to eq( original )
|
156
|
+
expect( copy ).to_not be( original )
|
157
|
+
expect( copy[:a] ).to eq( 1 )
|
158
|
+
expect( copy.key( 2 ) ).to eq( 'b' )
|
159
|
+
expect( copy.key( 2 ) ).to_not be( original.key(2) )
|
160
|
+
expect( copy[3] ).to eq( 'c' )
|
161
|
+
expect( copy[3] ).to_not be( original[3] )
|
162
|
+
end
|
163
|
+
|
164
|
+
it "makes distinct copies of deeply-nested Hashes" do
|
165
|
+
original = {
|
166
|
+
:a => {
|
167
|
+
:b => {
|
168
|
+
:c => 'd',
|
169
|
+
:e => 'f',
|
170
|
+
},
|
171
|
+
:g => 'h',
|
172
|
+
},
|
173
|
+
:i => 'j',
|
174
|
+
}
|
175
|
+
|
176
|
+
copy = Chione::DataUtilities.deep_copy( original )
|
177
|
+
|
178
|
+
expect( copy ).to eq( original )
|
179
|
+
expect( copy[:a][:b][:c] ).to eq( 'd' )
|
180
|
+
expect( copy[:a][:b][:c] ).to_not be( original[:a][:b][:c] )
|
181
|
+
expect( copy[:a][:b][:e] ).to eq( 'f' )
|
182
|
+
expect( copy[:a][:b][:e] ).to_not be( original[:a][:b][:e] )
|
183
|
+
expect( copy[:a][:g] ).to eq( 'h' )
|
184
|
+
expect( copy[:a][:g] ).to_not be( original[:a][:g] )
|
185
|
+
expect( copy[:i] ).to eq( 'j' )
|
186
|
+
expect( copy[:i] ).to_not be( original[:i] )
|
187
|
+
end
|
188
|
+
|
189
|
+
it "copies the default proc of copied Hashes" do
|
190
|
+
original = Hash.new {|h,k| h[ k ] = Set.new }
|
191
|
+
|
192
|
+
copy = Chione::DataUtilities.deep_copy( original )
|
193
|
+
|
194
|
+
expect( copy.default_proc ).to eq( original.default_proc )
|
195
|
+
end
|
196
|
+
|
197
|
+
it "preserves taintedness of copied objects" do
|
198
|
+
original = Object.new
|
199
|
+
original.taint
|
200
|
+
|
201
|
+
copy = Chione::DataUtilities.deep_copy( original )
|
202
|
+
|
203
|
+
expect( copy ).to_not be( original )
|
204
|
+
expect( copy ).to be_tainted()
|
205
|
+
end
|
206
|
+
|
207
|
+
it "preserves frozen-ness of copied objects" do
|
208
|
+
original = Object.new
|
209
|
+
original.freeze
|
210
|
+
|
211
|
+
copy = Chione::DataUtilities.deep_copy( original )
|
212
|
+
|
213
|
+
expect( copy ).to_not be( original )
|
214
|
+
expect( copy ).to be_frozen()
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
|
93
219
|
end
|
94
220
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chione
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Granger
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
X0qdrKi+2aZZ0NGuFj9AItBsVmAvkBGIpX4TEKQp5haEbPpmaqO5nIIhV26PXmyT
|
36
36
|
OMKv6pWsoS81vw5KAGBmfX8nht/Py90DQrbRvakATGI=
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2018-07-
|
38
|
+
date: 2018-07-19 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: loggability
|
@@ -197,28 +197,34 @@ dependencies:
|
|
197
197
|
requirements:
|
198
198
|
- - "~>"
|
199
199
|
- !ruby/object:Gem::Version
|
200
|
-
version: '0.
|
200
|
+
version: '0.4'
|
201
201
|
type: :development
|
202
202
|
prerelease: false
|
203
203
|
version_requirements: !ruby/object:Gem::Requirement
|
204
204
|
requirements:
|
205
205
|
- - "~>"
|
206
206
|
- !ruby/object:Gem::Version
|
207
|
-
version: '0.
|
207
|
+
version: '0.4'
|
208
208
|
- !ruby/object:Gem::Dependency
|
209
209
|
name: rdoc
|
210
210
|
requirement: !ruby/object:Gem::Requirement
|
211
211
|
requirements:
|
212
|
-
- - "
|
212
|
+
- - ">="
|
213
213
|
- !ruby/object:Gem::Version
|
214
|
-
version: '
|
214
|
+
version: '4.0'
|
215
|
+
- - "<"
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '6'
|
215
218
|
type: :development
|
216
219
|
prerelease: false
|
217
220
|
version_requirements: !ruby/object:Gem::Requirement
|
218
221
|
requirements:
|
219
|
-
- - "
|
222
|
+
- - ">="
|
223
|
+
- !ruby/object:Gem::Version
|
224
|
+
version: '4.0'
|
225
|
+
- - "<"
|
220
226
|
- !ruby/object:Gem::Version
|
221
|
-
version: '
|
227
|
+
version: '6'
|
222
228
|
- !ruby/object:Gem::Dependency
|
223
229
|
name: hoe
|
224
230
|
requirement: !ruby/object:Gem::Requirement
|
metadata.gz.sig
CHANGED
Binary file
|