chione 0.8.0 → 0.9.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 +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
|