mattock 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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