Class: Sycl::Hash
Overview
A Sycl::Hash is like a Hash, but creating one from an hash blesses any child Array or Hash objects into Sycl::Array or Sycl::Hash objects.
Hash contents can be accessed via “dot notation” (h.foo.bar means the same as h[‘bar’]). However, h.foo.bar dies if h does not exist, so get() and set() methods exist: h.get(‘foo.bar’) will return nil instead of dying if h does not exist. There is also a convenient deep_merge() that is like Hash#merge(), but also descends into and merges child nodes of the new hash.
Sycl::Hashes support YAML preprocessing and postprocessing, and having individual nodes marked as being rendered in inline style. YAML output is also always sorted by key.
Defined Under Namespace
Classes: MockNativeType
Class Method Summary collapse
Instance Method Summary collapse
- #<=>(another) ⇒ Object
-
#[]=(k, v) ⇒ Object
(also: #store)
Make sure that if we write to this hash, we promote any inputs to their Sycl equivalents.
-
#deep_merge(h) ⇒ Object
Deep merge two hashes (the new hash wins on conflicts).
- #encode_with(coder) ⇒ Object
-
#get(path) ⇒ Object
Safe dotted notation reads: h.get(‘foo.bar’) == h[‘bar’].
-
#initialize(*args) ⇒ Hash
constructor
A new instance of Hash.
- #merge!(h) ⇒ Object (also: #update)
- #method(sym) ⇒ Object
- #method_missing(method_symbol, *args, &block) ⇒ Object
-
#render_inline! ⇒ Object
Make this hash, or its children, rendered in inline/flow style YAML.
- #render_values_inline! ⇒ Object
-
#set(path, value) ⇒ Object
Dotted writes: h.set(‘foo.bar’ => ‘baz’) means h[‘bar’] = ‘baz’.
- #to_str ⇒ Object
- #to_yaml(opts = {}) ⇒ Object
- #yaml_postprocess(yaml) ⇒ Object
- #yaml_postprocessor(&block) ⇒ Object
- #yaml_preprocess! ⇒ Object
-
#yaml_preprocessor(&block) ⇒ Object
Hooks to run before and after YAML dumping.
Constructor Details
#initialize(*args) ⇒ Hash
Returns a new instance of Hash.
275 276 277 278 279 280 |
# File 'lib/sycl.rb', line 275 def initialize(*args) @yaml_preprocessor = nil @yaml_postprocessor = nil @yaml_style = nil super end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_symbol, *args, &block) ⇒ Object
322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/sycl.rb', line 322 def method_missing(method_symbol, *args, &block) key = method_symbol.to_s set = key.chomp!('=') if set self[key] = args.first elsif self.key?(key) self[key] else nil end end |
Class Method Details
.[](*args) ⇒ Object
282 283 284 |
# File 'lib/sycl.rb', line 282 def self.[](*args) Sycl::Hash.from_hash super end |
Instance Method Details
#<=>(another) ⇒ Object
397 398 399 |
# File 'lib/sycl.rb', line 397 def <=>(another) self.to_str <=> another.to_str end |
#[]=(k, v) ⇒ Object Also known as: store
Make sure that if we write to this hash, we promote any inputs to their Sycl equivalents. This lets dot notation, styled YAML, and other Sycl goodies continue.
301 302 303 304 305 306 |
# File 'lib/sycl.rb', line 301 def []=(k, v) unless v.is_a?(Sycl::Hash) || v.is_a?(Sycl::Array) v = Sycl::from_object(v) end super end |
#deep_merge(h) ⇒ Object
Deep merge two hashes (the new hash wins on conflicts). Hash or and Array objects in the new hash are promoted to Sycl variants.
379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/sycl.rb', line 379 def deep_merge(h) self.merge(h) do |key, v1, v2| if v1.is_a?(::Hash) && v2.is_a?(Sycl::Hash) self[key].deep_merge(v2) elsif v1.is_a?(::Hash) && v2.is_a?(::Hash) self[key].deep_merge(Sycl::Hash.from_hash(v2)) else self[key] = Sycl::from_object(v2) end end end |
#encode_with(coder) ⇒ Object
460 461 462 463 |
# File 'lib/sycl.rb', line 460 def encode_with(coder) coder.style = Psych::Nodes::Mapping::FLOW if @yaml_style == :inline coder.represent_map nil, sort end |
#get(path) ⇒ Object
339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/sycl.rb', line 339 def get(path) path = path.split(/\./) if path.is_a?(String) candidate = self while !path.empty? key = path.shift if candidate[key] candidate = candidate[key] else candidate = nil last end end candidate end |
#merge!(h) ⇒ Object Also known as: update
309 310 311 312 |
# File 'lib/sycl.rb', line 309 def merge!(h) h = Sycl::Hash.from_hash(h) unless h.is_a?(Sycl::Hash) super end |
#method(sym) ⇒ Object
449 450 451 |
# File 'lib/sycl.rb', line 449 def method(sym) sym == :to_yaml ? MockNativeType.new : super end |
#render_inline! ⇒ Object
Make this hash, or its children, rendered in inline/flow style YAML. The default is to render hashes in block (multi-line) style.
409 410 411 |
# File 'lib/sycl.rb', line 409 def render_inline! @yaml_style = :inline end |
#render_values_inline! ⇒ Object
413 414 415 416 417 |
# File 'lib/sycl.rb', line 413 def render_values_inline! self.values.each do |v| v.render_inline! if v.respond_to?(:render_inline!) end end |
#set(path, value) ⇒ Object
Dotted writes: h.set(‘foo.bar’ => ‘baz’) means h[‘bar’] = ‘baz’.
This will auto-vivify any missing intervening hash keys, and also promote Hash and Array objects in the input to Scyl variants.
360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/sycl.rb', line 360 def set(path, value) path = path.split(/\./) if path.is_a?(String) target = self while path.size > 1 key = path.shift if !(target.key?(key) && target[key].is_a?(::Hash)) target[key] = Sycl::Hash.new else target[key] = Sycl::Hash.from_hash(target[key]) end target = target[key] end target[path.first] = value end |
#to_str ⇒ Object
401 402 403 |
# File 'lib/sycl.rb', line 401 def to_str self.keys.sort.first end |
#to_yaml(opts = {}) ⇒ Object
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/sycl.rb', line 466 def to_yaml(opts = {}) yaml_preprocess! if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych' opts ||= {} opts[:line_width] ||= 999999 yaml = super else yaml = YAML::quick_emit(self, opts) do |out| out.map(nil, @yaml_style || to_yaml_style) do |map| sort.each { |k, v| map.add(k, v) } end end end yaml_postprocess yaml end |
#yaml_postprocess(yaml) ⇒ Object
434 435 436 |
# File 'lib/sycl.rb', line 434 def yaml_postprocess(yaml) @yaml_postprocessor ? @yaml_postprocessor.call(yaml) : yaml end |
#yaml_postprocessor(&block) ⇒ Object
426 427 428 |
# File 'lib/sycl.rb', line 426 def yaml_postprocessor(&block) @yaml_postprocessor = block if block_given? end |
#yaml_preprocess! ⇒ Object
430 431 432 |
# File 'lib/sycl.rb', line 430 def yaml_preprocess! @yaml_preprocessor.call(self) if @yaml_preprocessor end |
#yaml_preprocessor(&block) ⇒ Object
Hooks to run before and after YAML dumping
422 423 424 |
# File 'lib/sycl.rb', line 422 def yaml_preprocessor(&block) @yaml_preprocessor = block if block_given? end |