libis-workflow-mongoid 2.0.2 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/lib/libis/workflow/mongoid/base.rb +42 -3
- data/lib/libis/workflow/mongoid/job.rb +25 -3
- data/lib/libis/workflow/mongoid/run.rb +9 -4
- data/lib/libis/workflow/mongoid/version.rb +1 -1
- data/lib/libis/workflow/mongoid/work_item_base.rb +16 -4
- data/lib/libis/workflow/mongoid/workflow.rb +25 -3
- data/lib/map_with_indifferent_access.rb +20 -0
- data/lib/map_with_indifferent_access/list.rb +867 -0
- data/lib/map_with_indifferent_access/map.rb +833 -0
- data/lib/map_with_indifferent_access/normalization.rb +92 -0
- data/lib/map_with_indifferent_access/normalization/deep_normalizer.rb +104 -0
- data/lib/map_with_indifferent_access/values.rb +39 -0
- data/lib/map_with_indifferent_access/version.rb +3 -0
- data/lib/map_with_indifferent_access/wraps_collection.rb +152 -0
- data/libis-workflow-mongoid.gemspec +0 -1
- data/spec/items/test_dir_item.rb +1 -1
- data/spec/items/test_file_item.rb +3 -3
- data/spec/tasks/camelize_name.rb +1 -1
- data/spec/workflow_spec.rb +2 -2
- metadata +10 -2
@@ -0,0 +1,92 @@
|
|
1
|
+
require "map_with_indifferent_access/normalization/deep_normalizer"
|
2
|
+
|
3
|
+
module MapWithIndifferentAccess
|
4
|
+
module Normalization
|
5
|
+
class << self
|
6
|
+
# Deeply normalizes `Hash`-like and `Array`-like hash entry
|
7
|
+
# values and array items, preserving all of the existing key
|
8
|
+
# values (`String`, `Symbol`, or otherwise) from the inner
|
9
|
+
# collections.
|
10
|
+
#
|
11
|
+
# @see DeepNormalizer#call
|
12
|
+
def deeply_normalize(obj)
|
13
|
+
deep_basic_normalizer.call( obj )
|
14
|
+
end
|
15
|
+
|
16
|
+
# Deeply coerces keys to `Symbol` type.
|
17
|
+
#
|
18
|
+
# @see DeepNormalizer#call
|
19
|
+
def deeply_symbolize_keys(obj)
|
20
|
+
deep_key_symbolizer.call( obj )
|
21
|
+
end
|
22
|
+
|
23
|
+
# Deeply coerces keys to `String` type.
|
24
|
+
#
|
25
|
+
# @see DeepNormalizer#call
|
26
|
+
def deeply_stringify_keys(obj)
|
27
|
+
deep_key_stringifier.call( obj )
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def deep_basic_normalizer
|
33
|
+
@deep_basic_normalizer ||= DeepNormalizer.new( NullKeyStrategy )
|
34
|
+
end
|
35
|
+
|
36
|
+
def deep_key_symbolizer
|
37
|
+
@deep_key_symbolizer ||= DeepNormalizer.new( SymbolizationKeyStrategy )
|
38
|
+
end
|
39
|
+
|
40
|
+
def deep_key_stringifier
|
41
|
+
@deep_key_stringifier ||= DeepNormalizer.new( StringificationKeyStrategy )
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module KeyStrategy
|
46
|
+
def self.needs_coercion?(key)
|
47
|
+
raise NotImplementedError, "Including-module responsibility"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.coerce(key)
|
51
|
+
raise NotImplementedError, "Including-module responsibility"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module NullKeyStrategy
|
56
|
+
extend Normalization::KeyStrategy
|
57
|
+
|
58
|
+
def self.needs_coercion?(key)
|
59
|
+
false
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.coerce(key)
|
63
|
+
key
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module SymbolizationKeyStrategy
|
68
|
+
extend Normalization::KeyStrategy
|
69
|
+
|
70
|
+
def self.needs_coercion?(key)
|
71
|
+
!( Symbol === key )
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.coerce(key)
|
75
|
+
key.to_s.to_sym
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module StringificationKeyStrategy
|
80
|
+
extend Normalization::KeyStrategy
|
81
|
+
|
82
|
+
def self.needs_coercion?(key)
|
83
|
+
!( String === key )
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.coerce(key)
|
87
|
+
key.to_s
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module MapWithIndifferentAccess
|
2
|
+
module Normalization
|
3
|
+
|
4
|
+
class DeepNormalizer
|
5
|
+
attr_reader :strategy
|
6
|
+
|
7
|
+
# Initializes a new DeepNormalizer with a given object that
|
8
|
+
# extends {KeyStrategy}.
|
9
|
+
def initialize(strategy)
|
10
|
+
@strategy = strategy
|
11
|
+
end
|
12
|
+
|
13
|
+
# Given an `Array`-like or `Hash`-like object, returns a
|
14
|
+
# similar object with keys coerced according to the
|
15
|
+
# target {DeepNormalizer}'s strategy.
|
16
|
+
# Given an object that is not `Array`-like or `Hash`-like,
|
17
|
+
# then the given object is returned.
|
18
|
+
#
|
19
|
+
# During this process, any hash entry values or array
|
20
|
+
# items that are instances of
|
21
|
+
# {Map} or {List} are replaced with `Hash` or `Array`
|
22
|
+
# deconstructions respectively. If a {Map} or {List} is
|
23
|
+
# given, then the same type of object is returned.
|
24
|
+
#
|
25
|
+
# If a `Hash` or an object that resonds to `#to_hash` and
|
26
|
+
# `#each_pair` is given, then a `Hash` is returned. The
|
27
|
+
# same applies to each `Hash`/{Map} entry value or
|
28
|
+
# `Array`/{List} item that is traversed.
|
29
|
+
#
|
30
|
+
# If an `Array` or an object that resonds to `#to_ary` is
|
31
|
+
# given, then an `Array` is returned. The same applies to
|
32
|
+
# each `Hash`/{Map} entry value or `Array`/{List} item that
|
33
|
+
# is traversed.
|
34
|
+
#
|
35
|
+
# If any keys, `Hash` entry values, or `Array` items are
|
36
|
+
# replaced, then a new object is returned that includes
|
37
|
+
# those replacements. Otherwise, the given object is
|
38
|
+
# returned. In either case, the contents of `obj` are not
|
39
|
+
# modified.
|
40
|
+
def call(obj)
|
41
|
+
if WrapsCollection === obj
|
42
|
+
coerced_inner_col = recursively_coerce( obj )
|
43
|
+
Values.externalize( coerced_inner_col )
|
44
|
+
else
|
45
|
+
recursively_coerce( obj )
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def recursively_coerce(obj)
|
52
|
+
if ::Hash === obj
|
53
|
+
coerce_hash( obj )
|
54
|
+
elsif Map === obj
|
55
|
+
coerce_hash( obj.inner_map )
|
56
|
+
elsif ::Array === obj
|
57
|
+
coerce_array( obj )
|
58
|
+
elsif List === obj
|
59
|
+
coerce_array( obj.inner_array )
|
60
|
+
elsif obj.respond_to?(:to_hash) && obj.respond_to?(:each_pair)
|
61
|
+
coerce_hash( obj.to_hash )
|
62
|
+
elsif obj.respond_to?(:to_ary)
|
63
|
+
coerce_array( obj.to_ary )
|
64
|
+
else
|
65
|
+
obj
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def coerce_hash(obj)
|
70
|
+
does_need_key_coercion = obj.each_key.any?{ |key|
|
71
|
+
strategy.needs_coercion?( key )
|
72
|
+
}
|
73
|
+
result = does_need_key_coercion ? {} : obj
|
74
|
+
|
75
|
+
obj.each_pair do |(key,value)|
|
76
|
+
key = strategy.coerce( key ) if strategy.needs_coercion?( key )
|
77
|
+
new_value = recursively_coerce( value )
|
78
|
+
if result.equal?( obj )
|
79
|
+
unless new_value.equal?( value )
|
80
|
+
result = obj.dup
|
81
|
+
result[ key ] = new_value
|
82
|
+
end
|
83
|
+
else
|
84
|
+
result[ key ] = new_value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
def coerce_array( obj )
|
91
|
+
result = obj
|
92
|
+
obj.each_with_index do |item,i|
|
93
|
+
new_item = recursively_coerce(item)
|
94
|
+
unless new_item.equal?( item )
|
95
|
+
result = obj.dup if result.equal?( obj )
|
96
|
+
result[ i ] = new_item
|
97
|
+
end
|
98
|
+
end
|
99
|
+
result
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MapWithIndifferentAccess
|
2
|
+
|
3
|
+
module Values
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# Converts `obj` to a {Map} or {List} if possible, otherwise
|
7
|
+
# returns `obj`.
|
8
|
+
#
|
9
|
+
# @return [Map, List, Object]
|
10
|
+
def externalize(obj)
|
11
|
+
(
|
12
|
+
Map.try_convert( obj ) ||
|
13
|
+
List.try_convert( obj ) ||
|
14
|
+
obj
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
alias >> externalize
|
19
|
+
|
20
|
+
# Converts `obj`, which might be a {Map} or {List} to a
|
21
|
+
# `Hash` or `Array` if possible. Returns `obj` if no
|
22
|
+
# conversion is possible.
|
23
|
+
#
|
24
|
+
# @return [Hash, Array, Object]
|
25
|
+
def internalize(obj)
|
26
|
+
(
|
27
|
+
Map.try_deconstruct( obj ) ||
|
28
|
+
List.try_deconstruct( obj ) ||
|
29
|
+
obj
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias << internalize
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module MapWithIndifferentAccess
|
4
|
+
|
5
|
+
module WrapsCollection
|
6
|
+
extend Forwardable
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
# The encapsulated collection object.
|
10
|
+
attr_reader :inner_collection
|
11
|
+
|
12
|
+
# @!method length
|
13
|
+
# The number of entries in the collection.
|
14
|
+
#
|
15
|
+
# @return [Fixnum]
|
16
|
+
# @see #size
|
17
|
+
|
18
|
+
# @!method size
|
19
|
+
# The number of entries in the collection.
|
20
|
+
#
|
21
|
+
# @return [Fixnum]
|
22
|
+
# @see #length
|
23
|
+
|
24
|
+
# @!method empty?
|
25
|
+
# Returns `true` if the collection contains no entries.
|
26
|
+
#
|
27
|
+
# Returns `false` if the collection contains 1 or more
|
28
|
+
# entries.
|
29
|
+
#
|
30
|
+
# @return [Boolean]
|
31
|
+
|
32
|
+
# @!method _frozen?
|
33
|
+
# Returns true when the target object (the wrapper) is
|
34
|
+
# frozen.
|
35
|
+
#
|
36
|
+
# There are some cases in which this returns `false` when
|
37
|
+
# {#frozen?} would return `true`.
|
38
|
+
#
|
39
|
+
# @return [Boolean]
|
40
|
+
# @see #frozen?
|
41
|
+
|
42
|
+
# Using `class_eval` to hide the aliasing from YARD, so it
|
43
|
+
# does not document this alias to the implementation
|
44
|
+
# inherited from `Object` as an alias to the subsequent
|
45
|
+
# override.
|
46
|
+
class_eval 'alias _frozen? frozen?', __FILE__, __LINE__
|
47
|
+
|
48
|
+
# @!method tainted?
|
49
|
+
# Reflects the tainted-ness of its #inner_collection.
|
50
|
+
# @return [Boolean]
|
51
|
+
|
52
|
+
# @!method untrusted?
|
53
|
+
# Reflects the untrusted-ness of its #inner_collection.
|
54
|
+
# @return [Boolean]
|
55
|
+
|
56
|
+
# @!method frozen?
|
57
|
+
# Reflects the frozen-ness of its {#inner_collection}.
|
58
|
+
#
|
59
|
+
# Returns `true` when the {#inner_collection} is frozen (
|
60
|
+
# and the target/wrapper might be frozen or not).
|
61
|
+
#
|
62
|
+
# Returns `false` when the {#inner_collection} is not
|
63
|
+
# frozen (and neither is the target/wrapper).
|
64
|
+
#
|
65
|
+
# When the {#inner_collection} is frozen, but the target
|
66
|
+
# object is not, then the target behaves as if frozen in
|
67
|
+
# most ways, but some of the restrictions that Ruby applies
|
68
|
+
# to truly frozen (such as preventing instance methods from
|
69
|
+
# being dynamically added to the object) do not apply.
|
70
|
+
#
|
71
|
+
# @return [Boolean]
|
72
|
+
# @see #_frozen?
|
73
|
+
|
74
|
+
# @!method hash
|
75
|
+
# Compute a hash-code for this collection wrapper. Two
|
76
|
+
# wrappers with the same type and the same
|
77
|
+
# {#inner_collection} content will have the same hash code
|
78
|
+
# (and will match using {#eql?}).
|
79
|
+
#
|
80
|
+
# @return [Fixnum]
|
81
|
+
|
82
|
+
def_delegators(
|
83
|
+
:inner_collection,
|
84
|
+
:length,
|
85
|
+
:size,
|
86
|
+
:empty?,
|
87
|
+
:tainted?,
|
88
|
+
:untrusted?,
|
89
|
+
:frozen?,
|
90
|
+
:hash,
|
91
|
+
)
|
92
|
+
|
93
|
+
# @!method taint
|
94
|
+
# Causes the target's #inner_collection to be tainted.
|
95
|
+
|
96
|
+
# @!method untaint
|
97
|
+
# Causes the target's #inner_collection to be untainted.
|
98
|
+
|
99
|
+
# @!method untrust
|
100
|
+
# Causes the target's #inner_collection to be untrusted.
|
101
|
+
|
102
|
+
# @!method trust
|
103
|
+
# Causes the target's {#inner_collection} to be trusted.
|
104
|
+
|
105
|
+
[:taint, :untaint, :untrust, :trust ].each do |method_name|
|
106
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
107
|
+
def #{method_name}
|
108
|
+
inner_collection.#{method_name}
|
109
|
+
self
|
110
|
+
end
|
111
|
+
EOS
|
112
|
+
end
|
113
|
+
|
114
|
+
# Removes all entries from the target's {#inner_collection}.
|
115
|
+
def clear
|
116
|
+
inner_collection.clear
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
# Freezes both the target map and its {#inner_collection}
|
121
|
+
# object.
|
122
|
+
def freeze
|
123
|
+
super
|
124
|
+
inner_collection.freeze
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns `true` for another instance of the same class as
|
129
|
+
# the target where the target's {#inner_collection} is
|
130
|
+
# `#eql?` to the given object's {#inner_collection}. Returns
|
131
|
+
# `false` otherwise.
|
132
|
+
#
|
133
|
+
# @return [Boolean]
|
134
|
+
def eql?(other)
|
135
|
+
self.class == other.class &&
|
136
|
+
self.inner_collection.eql?( other.inner_collection )
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def initialize_dup(orig)
|
142
|
+
super
|
143
|
+
@inner_collection = inner_collection.dup
|
144
|
+
end
|
145
|
+
|
146
|
+
def initialize_clone(orig)
|
147
|
+
super
|
148
|
+
@inner_collection = inner_collection.clone
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
data/spec/items/test_dir_item.rb
CHANGED
@@ -15,15 +15,15 @@ class TestFileItem < TestItem
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def name
|
18
|
-
self.properties[
|
18
|
+
self.properties[:name] || super
|
19
19
|
end
|
20
20
|
|
21
21
|
def filesize
|
22
|
-
properties[
|
22
|
+
properties[:size]
|
23
23
|
end
|
24
24
|
|
25
25
|
def fixity_check(checksum)
|
26
|
-
properties[
|
26
|
+
properties[:checksum] == checksum
|
27
27
|
end
|
28
28
|
|
29
29
|
end
|
data/spec/tasks/camelize_name.rb
CHANGED
data/spec/workflow_spec.rb
CHANGED
@@ -190,8 +190,8 @@ STR
|
|
190
190
|
item = run.items.first
|
191
191
|
expect(item.nil?).to eq false
|
192
192
|
expect(item.is_a? TestDirItem).to eq true
|
193
|
-
expect(item.properties[
|
194
|
-
expect(item.properties[
|
193
|
+
expect(item.properties[:name]).to eq 'Items'
|
194
|
+
expect(item.properties[:ingest_failed]).to eq false
|
195
195
|
end
|
196
196
|
|
197
197
|
it 'move item in relation' do
|