mattock 0.9.0 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 058ff110aa5e5ffd99da0527d769e565d2219fd1
4
- data.tar.gz: 56845e99beb502e10826cd0baa17385ec49a66db
3
+ metadata.gz: 70b769461d13694dbd33d6aca28506eb472e8ae5
4
+ data.tar.gz: 27701d143e0ddd82f0edd468a2b7d8e82ef6a3e0
5
5
  SHA512:
6
- metadata.gz: 8c9ae840327f2fdf631b8505221b416fba46e2d635c928cfa9875225bb41ac0ace63261ad71c30891cc8f4a411a5466331da3ca325fdc107a8e3574b41392419
7
- data.tar.gz: f31d1b3427076cf6fd81ec8dc4d7361bd4e4e7e949e2e0dd0b4810c6964a50654f19ffe65fa7cdcfc03ac9021aca8b58e396b594e4519a619bab9755dc055f13
6
+ metadata.gz: c900dab527d13a9debdb1b7675476da4cca839c59fa2883831f968a3871b307a2114d139e1cb632d47fe50a91241bd869da57c70b55e2fbbdf8760b9ad5539a4
7
+ data.tar.gz: 8f0b1dfb07599a17df00ba078c591569164c023c721a9e367ade70ed76515577881206ad7e8d3980693415b2d811865f591cc7ed5bab3bbf236b6ea187c8a408
@@ -1,4 +1,4 @@
1
- require 'mattock/configurable'
1
+ require 'calibrate/configurable'
2
2
 
3
3
  module Mattock
4
4
  #Collects shared configuration management behavior for TaskLibs and Tasks
@@ -23,7 +23,7 @@ module Mattock
23
23
  #
24
24
  #For an overview see {TaskLib}
25
25
  module CascadingDefinition
26
- include Configurable
26
+ include Calibrate::Configurable
27
27
 
28
28
  def setup_cascade(*other_definitions)
29
29
  @runtime = false
@@ -1,4 +1,5 @@
1
1
  require 'mattock/cascading-definition'
2
+ require 'calibrate'
2
3
  require 'singleton' #Rake fails to require this properly
3
4
  require 'rake/task'
4
5
  require 'rake/file_task'
@@ -10,10 +11,10 @@ module Mattock
10
11
  # configuration block to change how a common task behaves, while still
11
12
  # overriding Rake API methods like Task#needed? and Task#timestamp
12
13
  module ConfigurableTask
13
- include Configurable
14
+ include Calibrate::Configurable
14
15
  include CascadingDefinition
15
16
  include DeferredDefinition
16
- include Configurable::DirectoryStructure
17
+ include Calibrate::Configurable::DirectoryStructure
17
18
 
18
19
  module ClassMethods
19
20
  def default_taskname(name)
@@ -21,9 +22,9 @@ module Mattock
21
22
  end
22
23
 
23
24
  def define_task(*args)
24
- configs = args.take_while{|arg| Configurable === arg}
25
+ configs = args.take_while{|arg| Calibrate::Configurable === arg}
25
26
  extracted_task_args = args[configs.length..-1]
26
- if extracted_task_args.any?{|arg| Configurable === arg}
27
+ if extracted_task_args.any?{|arg| Calibrate::Configurable === arg}
27
28
  raise "Mattock::Task classes should be created with parent configs, then Rake task args"
28
29
  end
29
30
 
@@ -56,8 +57,8 @@ module Mattock
56
57
 
57
58
  def self.included(sub)
58
59
  sub.extend ClassMethods
59
- Configurable.included(sub)
60
- Configurable::DirectoryStructure.included(sub)
60
+ Calibrate::Configurable.included(sub)
61
+ Calibrate::Configurable::DirectoryStructure.included(sub)
61
62
  DeferredDefinition.add_settings(sub)
62
63
  sub.setting :task_name
63
64
  sub.setting :task_args
@@ -50,7 +50,7 @@ module Mattock
50
50
  #configuration options are built using {Configurable}
51
51
  class TaskLib < ::Rake::TaskLib
52
52
  include CascadingDefinition
53
- include Configurable::DirectoryStructure
53
+ include Calibrate::Configurable::DirectoryStructure
54
54
 
55
55
  attr_writer :namespace_name
56
56
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mattock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Judson Lester
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-24 00:00:00.000000000 Z
11
+ date: 2015-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: corundum
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ~>
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.3.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: calibrate
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 0.0.1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 0.0.1
83
97
  description: |2+
84
98
  If Rake won't do it by itself, you oughtta Mattock.
85
99
 
@@ -99,43 +113,35 @@ extra_rdoc_files:
99
113
  - doc/README
100
114
  - doc/Specifications
101
115
  files:
102
- - yard_templates/default/module/setup.rb
103
- - yard_templates/default/module/html/setting_summary.erb
104
- - yard_templates/default/module/html/settings.erb
105
- - yard_templates/default/module/html/task_definition.erb
106
- - yard_templates/default/layout/html/setup.rb
107
- - yard_templates/default/layout/html/tasklib_list.erb
116
+ - doc/README
117
+ - doc/Specifications
118
+ - lib/mattock.rb
119
+ - lib/mattock/bundle-command-task.rb
120
+ - lib/mattock/cascading-definition.rb
108
121
  - lib/mattock/command-task.rb
109
122
  - lib/mattock/command-tasklib.rb
110
- - lib/mattock/testing/rake-example-group.rb
111
- - lib/mattock/template-host.rb
112
- - lib/mattock/yard_extensions.rb
123
+ - lib/mattock/configuration-store.rb
113
124
  - lib/mattock/remote-command-task.rb
114
- - lib/mattock/bundle-command-task.rb
115
- - lib/mattock/tasklib.rb
116
125
  - lib/mattock/task.rb
126
+ - lib/mattock/tasklib.rb
127
+ - lib/mattock/template-host.rb
117
128
  - lib/mattock/template-task.rb
118
- - lib/mattock/configurable.rb
119
- - lib/mattock/configurable/field-processor.rb
120
- - lib/mattock/configurable/proxy-value.rb
121
- - lib/mattock/configurable/instance-methods.rb
122
- - lib/mattock/configurable/class-methods.rb
123
- - lib/mattock/configurable/directory-structure.rb
124
- - lib/mattock/configurable/field-metadata.rb
125
- - lib/mattock/configuration-store.rb
126
- - lib/mattock/cascading-definition.rb
127
- - lib/mattock.rb
128
- - doc/README
129
- - doc/Specifications
129
+ - lib/mattock/testing/rake-example-group.rb
130
+ - lib/mattock/yard_extensions.rb
130
131
  - spec/command-task.rb
131
- - spec/tasklib.rb
132
- - spec/configurable.rb
133
132
  - spec/configuration-store.rb
134
- - spec/yard-extensions.rb
133
+ - spec/tasklib.rb
135
134
  - spec/template-host.rb
136
- - spec_help/spec_helper.rb
135
+ - spec/yard-extensions.rb
137
136
  - spec_help/gem_test_suite.rb
138
- homepage: http://nyarly.github.com/mattock/
137
+ - spec_help/spec_helper.rb
138
+ - yard_templates/default/layout/html/setup.rb
139
+ - yard_templates/default/layout/html/tasklib_list.erb
140
+ - yard_templates/default/module/html/setting_summary.erb
141
+ - yard_templates/default/module/html/settings.erb
142
+ - yard_templates/default/module/html/task_definition.erb
143
+ - yard_templates/default/module/setup.rb
144
+ homepage: https://git.lrdesign.com/judson/mattock/tree/master
139
145
  licenses:
140
146
  - MIT
141
147
  metadata: {}
@@ -145,7 +151,7 @@ rdoc_options:
145
151
  - --main
146
152
  - doc/README
147
153
  - --title
148
- - mattock-0.9.0 RDoc
154
+ - mattock-0.10.0 RDoc
149
155
  require_paths:
150
156
  - lib/
151
157
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -160,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
166
  version: '0'
161
167
  requirements: []
162
168
  rubyforge_project: mattock
163
- rubygems_version: 2.0.14
169
+ rubygems_version: 2.4.8
164
170
  signing_key:
165
171
  specification_version: 3
166
172
  summary: A powerful companion to Rake
@@ -1,29 +0,0 @@
1
- module Mattock
2
- #Handles setting options on objects it's mixed into
3
- #
4
- #Settings can have default values or be required (as opposed to defaulting to
5
- #nil). Settings and their defaults are inherited (and can be overridden) by
6
- #subclasses.
7
- #
8
- #Mattock also includes a yard-extension that will document settings of a
9
- #Configurable
10
- #
11
- #@example (see ClassMethods)
12
- module Configurable
13
- class Exception < ::StandardError
14
- end
15
-
16
- class NoDefaultValue < Exception
17
- def initialize(field_name, klass)
18
- super("No default value for field #{field_name} on class #{klass.name}")
19
- end
20
- end
21
- end
22
- end
23
-
24
- require 'mattock/configurable/field-metadata'
25
- require 'mattock/configurable/proxy-value'
26
- require 'mattock/configurable/field-processor'
27
- require 'mattock/configurable/class-methods'
28
- require 'mattock/configurable/instance-methods'
29
- require 'mattock/configurable/directory-structure'
@@ -1,227 +0,0 @@
1
- module Mattock
2
- module Configurable
3
- RequiredField = Object.new.freeze
4
-
5
- #Describes class level DSL & machinery for working with configuration
6
- #managment.
7
- #
8
- #@example
9
- # class ConfExample
10
- # include Configurable
11
- #
12
- # setting :foo
13
- # settings :bar => 1, :baz => 3
14
- # nil_fields :hoo, :ha, :harum
15
- # required_fields :must
16
- #
17
- # def initialize
18
- # setup_defaults
19
- # end
20
- # end
21
- #
22
- # ce = ConfExample.new
23
- # ce.bar #=> 1
24
- # ce.hoo #=> nil
25
- # ce.hoo = "hallo"
26
- # ce.check_required #=> raises error because :must and :foo aren't set
27
- module ClassMethods
28
- def inspect_instance(instance, indent="")
29
- field_names.map do |name|
30
- meta = field_metadata(name)
31
- "#{indent}#{meta.inspect_on(instance, indent * 2)}"
32
- end.join("\n")
33
- end
34
-
35
- def default_values
36
- @default_values ||= []
37
- end
38
-
39
- def field_names
40
- names = default_values.map{|field| field.name}
41
- if Configurable > superclass
42
- names | superclass.field_names
43
- else
44
- names
45
- end
46
- end
47
-
48
- def field_metadata(name)
49
- field = default_values.find{|field| field.name == name}
50
- if field.nil? and Configurable > superclass
51
- superclass.field_metadata(name)
52
- else
53
- field
54
- end
55
- end
56
-
57
- #@raises NoDefaultValue
58
- def default_value_for(name)
59
- field = field_metadata(name)
60
- raise NoDefaultValue.new(name,self) unless field.is?(:defaulting)
61
- return field.default_value
62
- end
63
-
64
- #Creates an anonymous Configurable - useful in complex setups for nested
65
- #settings
66
- #@example SSH options
67
- # setting :ssh => nested(:username => "me", :password => nil)
68
- def nested(hash=nil, &block)
69
- nested = Class.new(Struct)
70
- nested.settings(hash || {})
71
- if block_given?
72
- nested.instance_eval(&block)
73
- end
74
- return nested
75
- end
76
-
77
- #Quick list of setting fields with a default value of nil. Useful
78
- #especially with {CascadingDefinition#resolve_configuration}
79
- def nil_fields(*names)
80
- names.each do |name|
81
- setting(name, nil)
82
- end
83
- self
84
- end
85
- alias nil_field nil_fields
86
-
87
- #List fields with no default for with a value must be set before
88
- #definition.
89
- def required_fields(*names)
90
- names.each do |name|
91
- setting(name)
92
- end
93
- self
94
- end
95
- alias required_field required_fields
96
-
97
- #Defines a setting on this class - much like a attr_accessible call, but
98
- #allows for defaults and required settings
99
- def setting(name, default_value = RequiredField)
100
- name = name.to_sym
101
- metadata =
102
- if default_value == RequiredField
103
- FieldMetadata.new(name, nil).is(:required).isnt(:defaulting)
104
- else
105
- FieldMetadata.new(name, default_value)
106
- end
107
-
108
- attr_writer(name)
109
- define_method(metadata.reader_method) do
110
- metadata.value_on(self)
111
- end
112
-
113
- if existing = default_values.find{|field| field.name == name} and existing.default_value != default_value
114
- source_line = caller.drop_while{|line| /#{__FILE__}/ =~ line}.first
115
- warn "Changing default value of #{self.name}##{name} from #{existing.default_value.inspect} to #{default_value.inspect} (at: #{source_line})"
116
- end
117
- default_values << metadata
118
- metadata
119
- end
120
-
121
- def runtime_required_fields(*names)
122
- names.each do |name|
123
- runtime_setting(name)
124
- end
125
- self
126
- end
127
- alias runtime_required_field runtime_required_fields
128
-
129
- def runtime_setting(name, default_value = RequiredField)
130
- setting(name, default_value).is(:runtime)
131
- end
132
-
133
- #@param [Hash] hash Pairs of name/value to be converted into
134
- # setting/default
135
- def settings(hash)
136
- hash.each_pair do |name, value|
137
- setting(name, value)
138
- end
139
- return self
140
- end
141
- alias runtime_settings settings
142
-
143
- def set_defaults_on(instance)
144
- if Configurable > superclass
145
- superclass.set_defaults_on(instance)
146
- end
147
- default_values.each do |field|
148
- next unless field.is? :defaulting
149
- value = field.build_default_value
150
- instance.__send__(field.writer_method, value)
151
- end
152
- end
153
-
154
- def missing_required_fields_on(instance)
155
- missing = []
156
- if Configurable > superclass
157
- missing = superclass.missing_required_fields_on(instance)
158
- end
159
- default_values.each do |field|
160
- if field.missing_on?(instance)
161
- missing << field.name
162
- else
163
- set_value = instance.__send__(field.reader_method)
164
- if Configurable === set_value
165
- missing += set_value.class.missing_required_fields_on(set_value).map do |sub_field|
166
- [field.name, sub_field].join(".")
167
- end
168
- end
169
- end
170
- end
171
- return missing
172
- end
173
-
174
- def to_hash(obj)
175
- hash = if Configurable > superclass
176
- superclass.to_hash(obj)
177
- else
178
- {}
179
- end
180
- hash.merge( Hash[default_values.map{|field|
181
- begin
182
- value = obj.__send__(field.reader_method)
183
- value =
184
- case value
185
- when Configurable
186
- value.to_hash
187
- else
188
- value
189
- end
190
- [field.name, value]
191
- rescue NoMethodError
192
- end
193
- }])
194
- end
195
-
196
- def from_hash(obj, hash) #XXX It'd be really nice if this could report unused fields
197
- if Configurable > superclass
198
- superclass.from_hash(obj, hash)
199
- end
200
- default_values.each do |field|
201
- catch :next do
202
- key = field.reader_method.to_s
203
- value = hash.fetch(key.to_s) do
204
- key = key.to_sym
205
- hash.fetch(key) do
206
- throw :next
207
- end
208
- end
209
-
210
- existing_value = obj.__send__(field.reader_method)
211
- if Configurable === existing_value and value.is_a? Hash
212
- existing_value.from_hash(value)
213
- else
214
- obj.__send__(field.writer_method, value)
215
- end
216
- end
217
- end
218
- end
219
-
220
- def included(mod)
221
- mod.extend ClassMethods
222
- end
223
- end
224
-
225
- extend ClassMethods
226
- end
227
- end
@@ -1,163 +0,0 @@
1
- require 'rake'
2
-
3
- module Mattock
4
- module Configurable
5
- class MissingRelativePaths < Exception; end
6
-
7
- #XXX Consider making the actual dir/path settings r/o
8
- #Very easy to say
9
- # filename = "string"
10
- #rather than
11
- # filename.relative_path = "string"
12
- #and it isn't clear which (abs/rel) you mean
13
- #
14
- module DirectoryStructure
15
- class StructurePath
16
- include Configurable
17
-
18
- setting :absolute_path
19
- setting :relative_path
20
-
21
- alias abspath absolute_path
22
- alias relpath relative_path
23
-
24
- #No #path - ambiguous whether that would be abspath or pathname
25
-
26
- def initialize(rel_path)
27
- self.relative_path = rel_path unless rel_path == Configurable::RequiredField
28
- end
29
-
30
- def pathname
31
- @pathname ||=
32
- begin
33
- fail_unless_set(:absolute_path)
34
- require 'pathname'
35
- Pathname.new(absolute_path)
36
- end
37
- end
38
- alias path_name pathname
39
-
40
- def to_s
41
- fail_unless_set(:absolute_path)
42
- absolute_path
43
- end
44
-
45
- def inspect
46
- "<path: #{
47
- if field_unset?(:absolute_path)
48
- if field_unset?(:relative_path)
49
- "<<?>>"
50
- else
51
- "?/#{relative_path}"
52
- end
53
- else
54
- absolute_path.inspect
55
- end
56
- }>"
57
- end
58
- end
59
-
60
- module ClassMethods
61
- RequiredField = Configurable::RequiredField
62
-
63
- def root_paths
64
- @root_paths ||= []
65
- end
66
-
67
- def path_heirarchy
68
- @path_heirarchy ||= []
69
- end
70
- attr_writer :path_heirarchy
71
-
72
- def path_fields
73
- @path_fields ||= []
74
- end
75
-
76
- def dir(field_name, *args)
77
- rel_path = RequiredField
78
- if String === args.first
79
- rel_path = args.shift
80
- end
81
- parent_field = path(field_name, rel_path)
82
-
83
- self.path_heirarchy += args.map do |child_field|
84
- [parent_field, child_field]
85
- end
86
- return parent_field
87
- end
88
-
89
- def path(field_name, rel_path=RequiredField)
90
- field = setting(field_name, StructurePath.new(rel_path))
91
- root_paths << field
92
- path_fields << field
93
- return field
94
- end
95
-
96
- def resolve_path_on(instance, parent, child_field, missing_relatives)
97
- child = child_field.value_on(instance)
98
- return unless child.field_unset?(:absolute_path)
99
- if child.field_unset?(:relative_path)
100
- missing_relatives << child_field
101
- return
102
- end
103
- child.absolute_path = File::join(parent.absolute_path, child.relative_path)
104
- end
105
-
106
- def resolve_paths_on(instance)
107
- superclass_exception = nil
108
- if superclass < DirectoryStructure
109
- begin
110
- superclass.resolve_paths_on(instance)
111
- rescue MissingRelativePaths => mrp
112
- superclass_exception = mrp
113
- end
114
- end
115
- missing_relatives = []
116
-
117
- (root_paths - path_heirarchy.map{|_, child| child }).each do |field|
118
- resolve_path_on(instance, instance, field, missing_relatives)
119
- end
120
-
121
- path_heirarchy.reverse.each do |parent_field, child_field|
122
- next if missing_relatives.include?(parent_field)
123
- parent = parent_field.value_on(instance)
124
- resolve_path_on(instance, parent, child_field, missing_relatives)
125
- end
126
-
127
- case [missing_relatives.empty?, superclass_exception.nil?]
128
- when [true, false]
129
- raise superclass_exception
130
- when [false, true]
131
- raise MissingRelativePaths, "Required field#{missing_relatives.length == 1 ? "" : "s"} #{missing_relatives.map{|field| "#{field.name}.relative_path".inspect}.join(", ")} unset on #{self.inspect}"
132
- when [false, false]
133
- raise MissingRelativePaths, "Required field#{missing_relatives.length == 1 ? "" : "s"} #{missing_relatives.map{|field| "#{field.name}.relative_path".inspect}.join(", ")} unset on #{self.inspect}" + "\n" + superclass_exception.message
134
- end
135
-
136
- path_fields.each do |field|
137
- value = field.value_on(instance)
138
- next unless value.field_unset?(:relative_path)
139
- value.relative_path = value.absolute_path
140
- end
141
- end
142
- end
143
-
144
- def self.included(sub)
145
- sub.extend ClassMethods
146
- dir_path =
147
- if not (file_path = ::Rake.application.rakefile).nil?
148
- File::dirname(File::expand_path(file_path))
149
- elsif not (dir_path = ::Rake.application.original_dir).nil?
150
- dir_path
151
- else
152
- file_path = caller[0].split(':')[0]
153
- File::dirname(File::expand_path(file_path))
154
- end
155
- sub.setting :absolute_path, dir_path
156
- end
157
-
158
- def resolve_paths
159
- self.class.resolve_paths_on(self)
160
- end
161
- end
162
- end
163
- end
@@ -1,157 +0,0 @@
1
- module Mattock
2
- module Configurable
3
- class FieldMetadata
4
- attr_accessor :name, :default_value
5
-
6
- DEFAULT_PROPERTIES = {
7
- :copiable => true,
8
- :proxiable => true,
9
- :required => false,
10
- :runtime => false,
11
- :defaulting => true,
12
- }
13
- def initialize(name, value)
14
- @name = name
15
- @default_value = value
16
- @properties = DEFAULT_PROPERTIES.clone
17
- end
18
-
19
- def inspect
20
- set_props = DEFAULT_PROPERTIES.keys.find_all do |prop|
21
- @properties[prop]
22
- end
23
- "Field: #{name}: #{default_value.inspect} #{set_props.inspect}"
24
- end
25
-
26
- def inspect_on(instance, indent=nil)
27
- set_props = DEFAULT_PROPERTIES.keys.find_all do |prop|
28
- @properties[prop]
29
- end
30
- "Field: #{name}: #{value_on(instance).inspect} \n#{indent||""}(default: #{default_value.inspect} immediate: #{immediate_value_on(instance).inspect}) #{set_props.inspect}"
31
- end
32
-
33
- def validate_property_name(name)
34
- unless DEFAULT_PROPERTIES.has_key?(name)
35
- raise "Invalid field property #{name.inspect} - valid are: #{DEFAULT_PROPERTIES.keys.inspect}"
36
- end
37
- end
38
-
39
- def is?(property)
40
- validate_property_name(property)
41
- @properties[property]
42
- end
43
-
44
- def is_not?(property)
45
- validate_property_name(property)
46
- !@properties[property]
47
- end
48
- alias isnt? is_not?
49
-
50
- def is(property)
51
- validate_property_name(property)
52
- @properties[property] = true
53
- self
54
- end
55
-
56
- def is_not(property)
57
- validate_property_name(property)
58
- @properties[property] = false
59
- self
60
- end
61
- alias isnt is_not
62
-
63
- def ivar_name
64
- "@#{name}"
65
- end
66
-
67
- def writer_method
68
- "#{name}="
69
- end
70
-
71
- def reader_method
72
- name
73
- end
74
-
75
- def copy_from(instance)
76
- return if unset_on?(instance)
77
- copy_value(immediate_value_on(instance))
78
- end
79
-
80
- def build_default_value
81
- if Module === @default_value and Configurable > @default_value
82
- value = @default_value.new
83
- value.class.set_defaults_on(value)
84
- value
85
- else
86
- copy_value(@default_value)
87
- end
88
- end
89
-
90
- def copy_value(value)
91
- case value
92
- when Symbol, Numeric, NilClass, TrueClass, FalseClass
93
- value
94
- else
95
- if value.class == BasicObject
96
- value
97
- elsif value.respond_to?(:dup)
98
- value.dup
99
- elsif value.respond_to?(:clone)
100
- value.clone
101
- else
102
- value
103
- end
104
- end
105
- end
106
-
107
- def immediate_value_on(instance)
108
- instance.instance_variable_get(ivar_name)
109
- #instance.__send__(reader_method)
110
- end
111
-
112
- def value_on(instance)
113
- value = immediate_value_on(instance)
114
- if ProxyValue === value
115
- value.field.value_on(value.source)
116
- else
117
- value
118
- end
119
- end
120
-
121
- def set_on?(instance)
122
- return true unless instance.__send__(reader_method).nil?
123
- return false unless instance.instance_variable_defined?(ivar_name)
124
- value = immediate_value_on(instance)
125
- if ProxyValue === value
126
- value.field.set_on?(value.source)
127
- else
128
- true
129
- end
130
- end
131
-
132
- def unset_on?(instance)
133
- !set_on?(instance)
134
- end
135
-
136
- def missing_on?(instance)
137
- return false unless is?(:required)
138
- if instance.respond_to?(:runtime?) and !instance.runtime?
139
- return runtime_missing_on?(instance)
140
- else
141
- return !set_on?(instance)
142
- end
143
- end
144
-
145
- def runtime_missing_on?(instance)
146
- return false if is?(:runtime)
147
- return true unless instance.instance_variable_defined?(ivar_name)
148
- value = immediate_value_on(instance)
149
- if ProxyValue === value
150
- value.field.runtime_missing_on?(value.source)
151
- else
152
- false
153
- end
154
- end
155
- end
156
- end
157
- end
@@ -1,54 +0,0 @@
1
- module Mattock
2
- module Configurable
3
- class FieldProcessor
4
- def initialize(source)
5
- @source = source
6
- @field_names = filter(source.class.field_names)
7
- end
8
- attr_accessor :field_names
9
- attr_reader :source
10
-
11
- def filter(field_names)
12
- field_names.find_all do |name|
13
- source.class.field_metadata(name).is?(filter_attribute)
14
- end
15
- end
16
-
17
- def can_process(field, target)
18
- target.respond_to?(field.writer_method)
19
- end
20
-
21
- def to(target)
22
- field_names.each do |name|
23
- field = source.class.field_metadata(name)
24
- next unless can_process(field, target)
25
- target.__send__(field.writer_method, value(field))
26
- end
27
- end
28
- end
29
-
30
- class SettingsCopier < FieldProcessor
31
- def filter_attribute
32
- :copiable
33
- end
34
-
35
- def can_process(field, target)
36
- super and not( field.unset_on?(source) and field.unset_on?(target) )
37
- end
38
-
39
- def value(field)
40
- return field.copy_from(source)
41
- end
42
- end
43
-
44
- class SettingsProxier < FieldProcessor
45
- def filter_attribute
46
- :proxiable
47
- end
48
-
49
- def value(field)
50
- ProxyValue.new(source, field)
51
- end
52
- end
53
- end
54
- end
@@ -1,87 +0,0 @@
1
- require 'mattock/configurable/directory-structure'
2
-
3
- module Mattock
4
- module Configurable
5
- def initialize_copy(original)
6
- original.copy_settings_to(self)
7
- end
8
-
9
- def copy_settings
10
- SettingsCopier.new(self)
11
- end
12
-
13
- def copy_settings_to(other)
14
- copy_settings.to(other)
15
- self
16
- end
17
-
18
- def proxy_settings
19
- SettingsProxier.new(self)
20
- end
21
-
22
- def proxy_settings_to(other)
23
- proxy_settings.to(other)
24
- end
25
-
26
- def to_hash
27
- self.class.to_hash(self)
28
- end
29
-
30
- def from_hash(hash)
31
- self.class.from_hash(self, hash)
32
- end
33
-
34
- def unset_defaults_guard
35
- raise "Tried to check required settings before running setup_defaults"
36
- end
37
-
38
- #Call during initialize to set default values on settings - if you're using
39
- #Configurable outside of Mattock, be sure this gets called.
40
- def setup_defaults
41
- def self.unset_defaults_guard
42
- end
43
-
44
- self.class.set_defaults_on(self)
45
- self
46
- end
47
-
48
- #Checks that all required fields have be set, otherwise raises an error
49
- #@raise RuntimeError if any required fields are unset
50
- def check_required
51
- unset_defaults_guard
52
- missing = self.class.missing_required_fields_on(self)
53
- unless missing.empty?
54
- raise "Required field#{missing.length > 1 ? "s" : ""} #{missing.map{|field| field.to_s.inspect}.join(", ")} unset on #{self.inspect}"
55
- end
56
- self
57
- end
58
-
59
- def proxy_value
60
- ProxyDecorator.new(self)
61
- end
62
-
63
- #XXX deprecate
64
- def unset?(value)
65
- warn "#unset? is deprecated - use field_unset? instead"
66
- value.nil?
67
- end
68
-
69
- def field_unset?(name)
70
- self.class.field_metadata(name).unset_on?(self)
71
- end
72
-
73
- #Requires that a named field be set
74
- def fail_unless_set(name)
75
- if field_unset?(name)
76
- raise "Assertion failed: Field #{name} unset"
77
- end
78
- true
79
- end
80
- alias fail_if_unset fail_unless_set
81
-
82
- class Struct
83
- include Configurable
84
- include Configurable::DirectoryStructure
85
- end
86
- end
87
- end
@@ -1,30 +0,0 @@
1
- module Mattock
2
- module Configurable
3
- class ProxyValue
4
- def initialize(source, field)
5
- @source, @field = source, field
6
- end
7
- attr_reader :source, :field
8
-
9
- def inspect
10
- "#{self.class.name.split(':').last}: #{source.class.name}.#{field.inspect}"
11
- end
12
- end
13
-
14
- class ProxyDecorator
15
- def initialize(configurable)
16
- @configurable = configurable
17
- end
18
-
19
- def method_missing(name, *args, &block)
20
- unless block.nil? and args.empty?
21
- raise NoMethodError, "method `#{name}' not defined with arguments or block when proxied"
22
- end
23
- unless @configurable.respond_to?(name)
24
- raise NoMethodError, "cannot proxy `#{name}' - undefined on #{@configurable}"
25
- end
26
- return ProxyValue.new(@configurable, @configurable.class.field_metadata(name))
27
- end
28
- end
29
- end
30
- end
@@ -1,270 +0,0 @@
1
- require 'mattock'
2
-
3
- describe Mattock::Configurable do
4
- class TestSuperStruct
5
- include Mattock::Configurable
6
-
7
- setting(:three, 3)
8
- required_field(:four)
9
- required_field(:override)
10
- end
11
-
12
- class TestStruct < TestSuperStruct
13
- settings(:one => 1, :two => nested(:a => "a"){ required_field(:b)} )
14
- nil_field(:five)
15
-
16
- def override
17
- 17
18
- end
19
- end
20
-
21
- subject do
22
- TestStruct.new.setup_defaults
23
- end
24
-
25
- it "should set defaults" do
26
- subject.one.should == 1
27
- subject.two.a.should == "a"
28
- subject.three.should == 3
29
- subject.five.should be_nil
30
- end
31
-
32
- it "#to_hash" do
33
- hash = subject.to_hash
34
- hash[:one].should == 1
35
- hash[:two][:a].should == "a"
36
- end
37
-
38
- it "#from_hash" do
39
- subject.from_hash({:one => 111, "two" => { :a => "aaa" }})
40
-
41
- subject.one.should == 111
42
- subject.two.a.should == "aaa"
43
- end
44
-
45
- it "should complain about unset required fields" do
46
- expect do
47
- subject.check_required
48
- end.to raise_error
49
- end
50
-
51
- it "should complain about unset nested required fields" do
52
- subject.four = 4
53
- expect do
54
- subject.check_required
55
- end.to raise_error
56
- end
57
-
58
- it "should not complain when required fields are set" do
59
- subject.four = 4
60
- subject.two.b = "b"
61
- expect do
62
- subject.check_required
63
- end.to_not raise_error
64
- subject.override.should == 17
65
- end
66
-
67
- it "should inspect cleanly" do
68
- subject.inspect.should be_a(String)
69
- end
70
-
71
- describe "with DirectoryStructure" do
72
- class DirectoryThing
73
- include Mattock::Configurable
74
- include DirectoryStructure
75
-
76
- dir(:ephemeral_mountpoint,
77
- dir(:bundle_workdir, "bundle_workdir",
78
- path(:bundle_manifest),
79
- path(:credentials_archive, "aws-creds.tar.gz"),
80
- dir(:credentials_dir, "aws-creds",
81
- path(:private_key_file, "pk.pem"),
82
- path(:certificate_file, "cert.pem")
83
- )
84
- )
85
- )
86
-
87
- dir(:next_to_me, "rainbow", dir(:in_there, "a_place", path(:nearby, "a.file")))
88
-
89
- path(:loose_path, "here")
90
- end
91
-
92
- describe "distinctness" do
93
- let :one do
94
- DirectoryThing.new.tap do |thing|
95
- thing.setup_defaults
96
- end
97
- end
98
-
99
- let :other do
100
- DirectoryThing.new.tap do |thing|
101
- thing.setup_defaults
102
- end
103
- end
104
-
105
- it "should have same values" do
106
- one.bundle_workdir.relative_path.should == other.bundle_workdir.relative_path
107
- end
108
-
109
- it "should have different actual objects" do
110
- one.bundle_workdir.relative_path.should_not equal other.bundle_workdir.relative_path
111
- one.bundle_workdir.should_not equal other.bundle_workdir
112
- end
113
-
114
- end
115
-
116
- def subject
117
- DirectoryThing.new.tap do |thing|
118
- thing.setup_defaults
119
- end
120
- end
121
-
122
- it "should complain about missing fields" do
123
- expect do
124
- subject.check_required
125
- end.to raise_error(/Required field/)
126
- end
127
-
128
- it "should inspect cleanly" do
129
- subject.inspect.should be_a(String)
130
- end
131
-
132
- describe "with root path configured, but missing a relative path" do
133
- def subject
134
- DirectoryThing.new.tap do |thing|
135
- thing.setup_defaults
136
- thing.ephemeral_mountpoint.absolute_path = "/tmp"
137
- thing.resolve_paths
138
- end
139
- end
140
-
141
- it "should complain about missing fields" do
142
- expect do
143
- subject.check_required
144
- end.to raise_error(/Required field/)
145
- end
146
- end
147
-
148
- describe "with required paths configured" do
149
- def subject
150
- DirectoryThing.new.tap do |thing|
151
- thing.setup_defaults
152
- thing.ephemeral_mountpoint.absolute_path = "/tmp"
153
- thing.bundle_manifest.relative_path = "image.manifest.xml"
154
- thing.resolve_paths
155
- end
156
- end
157
-
158
- it "should not complain about required fields" do
159
- expect do
160
- subject.check_required
161
- end.not_to raise_error
162
- end
163
-
164
- its("nearby.absolute_path"){ should =~ %r"rainbow/a_place/a.file$"}
165
- its("nearby.absolute_path"){ should =~ %r"^#{subject.absolute_path}"}
166
-
167
- its("certificate_file.absolute_path"){ should == "/tmp/bundle_workdir/aws-creds/cert.pem" }
168
- its("bundle_manifest.absolute_path"){ should == "/tmp/bundle_workdir/image.manifest.xml" }
169
- its("credentials_dir.absolute_path"){ should == "/tmp/bundle_workdir/aws-creds" }
170
- end
171
- end
172
-
173
- describe "multiple instances" do
174
- class MultiSource
175
- include Mattock::Configurable
176
-
177
- setting :one, 1
178
- setting :nest, nested{
179
- setting :two, 2
180
- }
181
- end
182
-
183
- let :first do
184
- MultiSource.new.setup_defaults
185
- end
186
-
187
- let :second do
188
- MultiSource.new.setup_defaults
189
- end
190
-
191
- before :each do
192
- first.one = "one"
193
- first.nest.two = "two"
194
- second
195
- end
196
-
197
- it "should not have any validation errors" do
198
- expect do
199
- first.check_required
200
- second.check_required
201
- end.not_to raise_error
202
- end
203
-
204
- it "should accurately reflect settings" do
205
- first.one.should == "one"
206
- second.one.should == 1
207
-
208
- first.nest.two.should == "two"
209
- second.nest.two.should == 2
210
- end
211
- end
212
-
213
- describe "copying settings" do
214
- class LeftStruct
215
- include Mattock::Configurable
216
-
217
- setting(:normal, "1")
218
- setting(:nested, nested{
219
- setting :value, "2"
220
- })
221
- setting(:no_copy, 2).isnt(:copiable)
222
- setting(:no_proxy, 3).isnt(:proxiable)
223
- setting(:no_nothing, 4).isnt(:copiable).isnt(:proxiable)
224
- setting(:not_on_target, 5)
225
- end
226
-
227
- class RightStruct
228
- include Mattock::Configurable
229
-
230
- required_fields(:normal, :nested, :no_copy, :no_proxy, :no_nothing)
231
- end
232
-
233
- let :left do
234
- LeftStruct.new.setup_defaults
235
- end
236
-
237
- let :right do
238
- RightStruct.new.setup_defaults
239
- end
240
-
241
- it "should make copies not references" do
242
- left.copy_settings_to(right)
243
- right.normal.should == left.normal
244
- right.normal.should_not equal(left.normal)
245
- right.nested.value.should == left.nested.value
246
- right.nested.should_not equal(left.nested)
247
- right.nested.value.should_not equal left.nested.value
248
- end
249
-
250
- it "should not copy no_copy" do
251
- left.copy_settings_to(right)
252
- right.field_unset?(:normal).should be_false
253
- right.normal.should == "1"
254
- right.field_unset?(:no_copy).should be_true
255
- right.field_unset?(:no_proxy).should be_false
256
- right.no_proxy.should == 3
257
- right.field_unset?(:no_nothing).should be_true
258
- end
259
-
260
- it "should not proxy no_proxy" do
261
- left.proxy_settings.to(right)
262
- right.field_unset?(:normal).should be_false
263
- right.normal.should == "1"
264
- right.field_unset?(:no_copy).should be_false
265
- right.no_copy.should == 2
266
- right.field_unset?(:no_proxy).should be_true
267
- right.field_unset?(:no_nothing).should be_true
268
- end
269
- end
270
- end