diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2016-06-27 15:38:28 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2016-06-27 15:42:06 -0700 |
commit | 86fa507226b484a71a45ef6129840bc3928be6b7 (patch) | |
tree | b6f9efaedd634dbc61418ceb78817b91af1889df /lib/chef/node/common_api.rb | |
parent | 945f23be7a43d90ae7ed402d05363b3ff0c11bff (diff) | |
download | chef-lcg/attributes-v1.1.tar.gz |
Attributes v1.1 changeslcg/attributes-v1.1
- fixes *_unless behavior and set_unless_value_present hack from Chef 12
- simplifies rm_* code
- introduces functional read/write/unlink/exist? API
- deprecates method_missing access to attributes for Chef 13
- deprecates set/set_unless aliases for Chef 14
- removes MultiMash mess that I wrote for Chef 13
https://github.com/chef/chef/pull/5029 for more details
Diffstat (limited to 'lib/chef/node/common_api.rb')
-rw-r--r-- | lib/chef/node/common_api.rb | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/chef/node/common_api.rb b/lib/chef/node/common_api.rb new file mode 100644 index 0000000000..6f921e15aa --- /dev/null +++ b/lib/chef/node/common_api.rb @@ -0,0 +1,124 @@ +#-- +# Copyright:: Copyright 2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + class Node + # shared API between VividMash and ImmutableMash, writer code can be + # 'shared' to keep it logically in this file by adding them to the + # block list in ImmutableMash. + module CommonAPI + # method-style access to attributes + + def valid_container?(obj, key) + return obj.is_a?(Hash) || (obj.is_a?(Array) && key.is_a?(Fixnum)) + end + + private :valid_container? + + # - autovivifying / autoreplacing writer + # - non-container-ey intermediate objects are replaced with hashes + def write(*args, &block) + value = block_given? ? yield : args.pop + last = args.pop + prev_memo = prev_key = nil + chain = args.inject(self) do |memo, key| + if !valid_container?(memo, key) + prev_memo[prev_key] = {} + memo = prev_memo[prev_key] + end + prev_memo = memo + prev_key = key + memo[key] + end + if !valid_container?(chain, last) + prev_memo[prev_key] = {} + chain = prev_memo[prev_key] + end + chain[last] = value + end + + # this autovivifies, but can throw NoSuchAttribute when trying to access #[] on + # something that is not a container ("schema violation" issues). + # + def write!(*args, &block) + value = block_given? ? yield : args.pop + last = args.pop + obj = args.inject(self) do |memo, key| + raise Chef::Exceptions::AttributeTypeMismatch unless valid_container?(memo, key) + memo[key] + end + raise Chef::Exceptions::AttributeTypeMismatch unless valid_container?(obj, last) + obj[last] = value + end + + # FIXME:(?) does anyone need a non-autovivifying writer for attributes that throws exceptions? + + # return true or false based on if the attribute exists + def exist?(*path) + path.inject(self) do |memo, key| + return false unless valid_container?(memo, key) + if memo.is_a?(Hash) + if memo.key?(key) + memo[key] + else + return false + end + elsif memo.is_a?(Array) + if memo.length > key + memo[key] + else + return false + end + end + end + return true + end + + # this is a safe non-autovivifying reader that returns nil if the attribute does not exist + def read(*path) + begin + read!(*path) + rescue Chef::Exceptions::NoSuchAttribute + nil + end + end + + # non-autovivifying reader that throws an exception if the attribute does not exist + def read!(*path) + raise Chef::Exceptions::NoSuchAttribute unless exist?(*path) + path.inject(self) do |memo, key| + memo[key] + end + end + + # FIXME:(?) does anyone really like the autovivifying reader that we have and wants the same behavior? readers that write? ugh... + + def unlink(*path, last) + hash = path.empty? ? self : read(*path) + return nil unless hash.is_a?(Hash) || hash.is_a?(Array) + root.top_level_breadcrumb ||= last + hash.delete(last) + end + + def unlink!(*path) + raise Chef::Exceptions::NoSuchAttribute unless exist?(*path) + unlink(*path) + end + + end + end +end |