buff-extensions 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p429
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ script: "bundle exec thor spec"
2
+ language: ruby
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - jruby-19mode
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,24 @@
1
+ # Contributing
2
+
3
+ ## Running tests
4
+
5
+ ### Install prerequisites
6
+
7
+ Install the latest version of [Bundler](http://gembundler.com)
8
+
9
+ $ gem install bundler
10
+
11
+ Clone the project
12
+
13
+ $ git clone git://github.com/RiotGames/buff-extensions.git
14
+
15
+ and run:
16
+
17
+ $ cd buff-extensions
18
+ $ bundle install
19
+
20
+ Bundler will install all gems and their dependencies required for testing and developing.
21
+
22
+ ### Running unit (RSpec) tests
23
+
24
+ $ bundle exec guard start
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,15 @@
1
+ notification :off
2
+
3
+ guard "spork" do
4
+ watch('Gemfile')
5
+ watch('spec/spec_helper.rb') { :rspec }
6
+ watch(%r{^spec/support/.+\.rb$}) { :rspec }
7
+ end
8
+
9
+ guard "rspec", cli: "--color --drb --format Fuubar", all_on_start: false, all_after_pass: false do
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+
12
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
13
+ watch('spec/spec_helper.rb') { "spec" }
14
+ watch(%r{^spec/support/.+\.rb$}) { "spec" }
15
+ end
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Copyright 2012-2013 Riot Games
2
+
3
+ Jamie Winsor (<reset@riotgames.com>)
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Buff::Extensions
2
+ [![Gem Version](https://badge.fury.io/rb/buff-extensions.png)](http://badge.fury.io/rb/buff-extensions)
3
+ [![Build Status](https://travis-ci.org/RiotGames/buff-extensions.png?branch=master)](https://travis-ci.org/RiotGames/buff-extensions)
4
+
5
+ Extensions to Core Ruby classes
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'buff-extensions'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install buff-extensions
20
+
21
+ ## Usage
22
+
23
+ Using it as a mixin
24
+
25
+ require 'buff/extensions'
26
+
27
+ class PowerHash
28
+ include Buff::Extensions::DottedPaths
29
+ end
30
+
31
+ # Authors and Contributors
32
+
33
+ * Jamie Winsor (<reset@riotgames.com>)
34
+
35
+ Thank you to all of our [Contributors](https://github.com/RiotGames/buff-extensions/graphs/contributors), testers, and users.
data/Thorfile ADDED
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require 'bundler'
5
+ require 'bundler/setup'
6
+ require 'buff/ruby_engine'
7
+ require 'buff/extensions/version'
8
+
9
+ class Default < Thor
10
+ extend Buff::RubyEngine
11
+
12
+ unless jruby?
13
+ require 'thor/rake_compat'
14
+
15
+ include Thor::RakeCompat
16
+ Bundler::GemHelper.install_tasks
17
+
18
+ desc "build", "Build buff-extensions-#{Buff::Extensions::VERSION}.gem into the pkg directory"
19
+ def build
20
+ Rake::Task["build"].execute
21
+ end
22
+
23
+ desc "install", "Build and install buff-extensions-#{Buff::Extensions::VERSION}.gem into system gems"
24
+ def install
25
+ Rake::Task["install"].execute
26
+ end
27
+
28
+ desc "release", "Create tag v#{Buff::Extensions::VERSION} and build and push buff-extensions-#{Buff::Extensions::VERSION}.gem to Rubygems"
29
+ def release
30
+ Rake::Task["release"].execute
31
+ end
32
+ end
33
+
34
+ class Spec < Thor
35
+ namespace :spec
36
+ default_task :unit
37
+
38
+ desc "unit", "run the project's unit tests"
39
+ def unit
40
+ exec "rspec --color --format=documentation spec"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'buff/extensions/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "buff-extensions"
8
+ spec.version = Buff::Extensions::VERSION
9
+ spec.authors = ["Jamie Winsor"]
10
+ spec.email = ["reset@riotgames.com"]
11
+ spec.description = %q{Extensions to Core Ruby classes}
12
+ spec.summary = spec.description
13
+ spec.homepage = "https://github.com/RiotGames/buff-extensions"
14
+ spec.license = "Apache 2.0"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^spec/})
19
+ spec.require_paths = ["lib"]
20
+ spec.required_ruby_version = ">= 1.9.2"
21
+
22
+ spec.add_development_dependency "buff-ruby_engine", "~> 0.1"
23
+ spec.add_development_dependency "thor", "~> 0.18.0"
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "fuubar"
28
+ spec.add_development_dependency "guard"
29
+ spec.add_development_dependency "guard-rspec"
30
+ spec.add_development_dependency "guard-spork"
31
+ spec.add_development_dependency "spork"
32
+ end
@@ -0,0 +1,9 @@
1
+ module Boolean; end
2
+
3
+ class TrueClass
4
+ include Boolean
5
+ end
6
+
7
+ class FalseClass
8
+ include Boolean
9
+ end
@@ -0,0 +1,124 @@
1
+ require 'buff/extensions/object'
2
+
3
+ module Buff
4
+ module Extensions
5
+ module DottedPaths
6
+ class << self
7
+ def included(base)
8
+ base.send(:extend, ClassMethods)
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ # Create a new Hash containing other nested Hashes from a string containing
14
+ # a dotted path. A Hash will be created and assigned to a key of another Hash
15
+ # for each entry in the dotted path.
16
+ #
17
+ # If a value is provided for the optional seed argument then the value of the
18
+ # deepest nested key will be set to the given value. If no value is provided
19
+ # the value of the key will be nil.
20
+ #
21
+ # @example creating a nested hash from a dotted path
22
+ #
23
+ # Hash.from_dotted_path("deep.nested.hash") =>
24
+ # {
25
+ # "deep" => {
26
+ # "nested" => {
27
+ # "hash" => nil
28
+ # }
29
+ # }
30
+ # }
31
+ #
32
+ #
33
+ # @example specifying a seed value
34
+ #
35
+ # Hash.from_dotted_path("deep.nested.hash", :seed_value) =>
36
+ # {
37
+ # "deep" => {
38
+ # "nested" => {
39
+ # "hash" => :seed_value
40
+ # }
41
+ # }
42
+ # }
43
+ #
44
+ # @param [String, Symbol, Array] dotpath
45
+ # @param [Object] seed (nil)
46
+ # @param [Hash] target (self.new)
47
+ #
48
+ # @return [Hash]
49
+ def from_dotted_path(dotpath, seed = nil, target = self.new)
50
+ case dotpath
51
+ when String, Symbol
52
+ from_dotted_path(dotpath.to_s.split("."), seed)
53
+ when Array
54
+ if dotpath.empty?
55
+ return target
56
+ end
57
+
58
+ key = dotpath.pop
59
+
60
+ if target.empty?
61
+ target[key] = seed
62
+ from_dotted_path(dotpath, seed, target)
63
+ else
64
+ new_target = self.new
65
+ new_target[key] = target
66
+ from_dotted_path(dotpath, seed, new_target)
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # Return the value of the nested hash key from the given dotted path
73
+ #
74
+ # @example
75
+ #
76
+ # nested_hash = {
77
+ # "deep" => {
78
+ # "nested" => {
79
+ # "hash" => :seed_value
80
+ # }
81
+ # }
82
+ # }
83
+ #
84
+ # nested_hash.dig('deep.nested.hash') => :seed_value
85
+ #
86
+ # @param [String] path
87
+ #
88
+ # @return [Object, nil]
89
+ def dig(path)
90
+ return nil unless path.present?
91
+
92
+ parts = path.split('.', 2)
93
+ match = self[parts[0].to_s].nil? ? self[parts[0].to_sym] : self[parts[0].to_s]
94
+ if !parts[1] or match.nil?
95
+ match
96
+ else
97
+ match.dig(parts[1])
98
+ end
99
+ end
100
+
101
+ # Returns an array of dotted paths from the keys, values of this Hash. Values which are
102
+ # nested Hashes will also recurred into and their paths will be added properly.
103
+ #
104
+ # @param [Hash] source
105
+ # @param [Array] acc
106
+ # @param [Array] namespace
107
+ #
108
+ # @return [Array<String>]
109
+ def dotted_paths(source = self, acc = Array.new, namespace = Array.new)
110
+ if source.is_a?(Hash) && !source.empty?
111
+ source.each do |key, value|
112
+ branch = namespace.dup
113
+ branch << key
114
+ dotted_paths(value, acc, branch)
115
+ end
116
+ else
117
+ acc << namespace.join('.')
118
+ end
119
+
120
+ acc
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,144 @@
1
+ module Buff
2
+ module Extensions
3
+ # Borrowd and modified from
4
+ # {https://raw.github.com/rails/rails/master/activesupport/lib/active_support/core_ext/hash/keys.rb}
5
+ module KeyTransforms
6
+ # Return a new hash with all keys converted using the block operation.
7
+ #
8
+ # hash = { name: 'Rob', age: '28' }
9
+ #
10
+ # hash.transform_keys{ |key| key.to_s.upcase }
11
+ # # => { "NAME" => "Rob", "AGE" => "28" }
12
+ def transform_keys
13
+ result = {}
14
+ each_key do |key|
15
+ result[yield(key)] = self[key]
16
+ end
17
+ result
18
+ end
19
+
20
+ # Destructively convert all keys using the block operations.
21
+ # Same as transform_keys but modifies +self+.
22
+ def transform_keys!
23
+ keys.each do |key|
24
+ self[yield(key)] = delete(key)
25
+ end
26
+ self
27
+ end
28
+
29
+ # Return a new hash with all keys converted to strings.
30
+ #
31
+ # hash = { name: 'Rob', age: '28' }
32
+ #
33
+ # hash.stringify_keys
34
+ # #=> { "name" => "Rob", "age" => "28" }
35
+ def stringify_keys
36
+ transform_keys { |key| key.to_s }
37
+ end
38
+
39
+ # Destructively convert all keys to strings. Same as
40
+ # +stringify_keys+, but modifies +self+.
41
+ def stringify_keys!
42
+ transform_keys! { |key| key.to_s }
43
+ end
44
+
45
+ # Return a new hash with all keys converted to symbols, as long as
46
+ # they respond to +to_sym+.
47
+ #
48
+ # hash = { 'name' => 'Rob', 'age' => '28' }
49
+ #
50
+ # hash.symbolize_keys
51
+ # #=> { name: "Rob", age: "28" }
52
+ def symbolize_keys
53
+ transform_keys { |key| key.to_sym rescue key }
54
+ end
55
+ alias_method :to_options, :symbolize_keys
56
+
57
+ # Destructively convert all keys to symbols, as long as they respond
58
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
59
+ def symbolize_keys!
60
+ transform_keys! { |key| key.to_sym rescue key }
61
+ end
62
+ alias_method :to_options!, :symbolize_keys!
63
+
64
+ # Validate all keys in a hash match <tt>*valid_keys</tt>, raising ArgumentError
65
+ # on a mismatch. Note that keys are NOT treated indifferently, meaning if you
66
+ # use strings for keys but assert symbols as keys, this will fail.
67
+ #
68
+ # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
69
+ # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name"
70
+ # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
71
+ def assert_valid_keys(*valid_keys)
72
+ valid_keys.flatten!
73
+ each_key do |k|
74
+ raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
75
+ end
76
+ end
77
+
78
+ # Return a new hash with all keys converted by the block operation.
79
+ # This includes the keys from the root hash and from all
80
+ # nested hashes.
81
+ #
82
+ # hash = { person: { name: 'Rob', age: '28' } }
83
+ #
84
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
85
+ # # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } }
86
+ def deep_transform_keys(&block)
87
+ result = {}
88
+ each do |key, value|
89
+ result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
90
+ end
91
+ result
92
+ end
93
+
94
+ # Destructively convert all keys by using the block operation.
95
+ # This includes the keys from the root hash and from all
96
+ # nested hashes.
97
+ def deep_transform_keys!(&block)
98
+ keys.each do |key|
99
+ value = delete(key)
100
+ self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
101
+ end
102
+ self
103
+ end
104
+
105
+ # Return a new hash with all keys converted to strings.
106
+ # This includes the keys from the root hash and from all
107
+ # nested hashes.
108
+ #
109
+ # hash = { person: { name: 'Rob', age: '28' } }
110
+ #
111
+ # hash.deep_stringify_keys
112
+ # # => { "person" => { "name" => "Rob", "age" => "28" } }
113
+ def deep_stringify_keys
114
+ deep_transform_keys { |key| key.to_s }
115
+ end
116
+
117
+ # Destructively convert all keys to strings.
118
+ # This includes the keys from the root hash and from all
119
+ # nested hashes.
120
+ def deep_stringify_keys!
121
+ deep_transform_keys! { |key| key.to_s }
122
+ end
123
+
124
+ # Return a new hash with all keys converted to symbols, as long as
125
+ # they respond to +to_sym+. This includes the keys from the root hash
126
+ # and from all nested hashes.
127
+ #
128
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
129
+ #
130
+ # hash.deep_symbolize_keys
131
+ # # => { person: { name: "Rob", age: "28" } }
132
+ def deep_symbolize_keys
133
+ deep_transform_keys { |key| key.to_sym rescue key }
134
+ end
135
+
136
+ # Destructively convert all keys to symbols, as long as they respond
137
+ # to +to_sym+. This includes the keys from the root hash and from all
138
+ # nested hashes.
139
+ def deep_symbolize_keys!
140
+ deep_transform_keys! { |key| key.to_sym rescue key }
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,19 @@
1
+ module Buff
2
+ module Extensions
3
+ module ReverseMerge
4
+ # @param [Hash] other
5
+ #
6
+ # @return [Hash]
7
+ def reverse_merge(other)
8
+ other.merge(self)
9
+ end
10
+
11
+ # @param [Hash] other
12
+ #
13
+ # @return [Hash]
14
+ def reverse_merge!(other)
15
+ merge!(other) { |key, old, new| old }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'hash/dotted_paths'
2
+ require_relative 'hash/key_transforms'
3
+ require_relative 'hash/reverse_merge'
4
+
5
+ class Hash
6
+ include Buff::Extensions::DottedPaths
7
+ include Buff::Extensions::KeyTransforms
8
+ include Buff::Extensions::ReverseMerge
9
+ end
@@ -0,0 +1,106 @@
1
+ # Borrowed and modified from
2
+ # {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/object/blank.rb}
3
+
4
+ class Object
5
+ # An object is blank if it's false, empty, or a whitespace string.
6
+ # For example, '', ' ', +nil+, [], and {} are all blank.
7
+ #
8
+ # This simplifies:
9
+ #
10
+ # if address.nil? || address.empty?
11
+ #
12
+ # ...to:
13
+ #
14
+ # if address.blank?
15
+ def blank?
16
+ respond_to?(:empty?) ? empty? : !self
17
+ end
18
+
19
+ # An object is present if it's not <tt>blank?</tt>.
20
+ def present?
21
+ !blank?
22
+ end
23
+
24
+ # Returns object if it's <tt>present?</tt> otherwise returns +nil+.
25
+ # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
26
+ #
27
+ # This is handy for any representation of objects where blank is the same
28
+ # as not present at all. For example, this simplifies a common check for
29
+ # HTTP POST/query parameters:
30
+ #
31
+ # state = params[:state] if params[:state].present?
32
+ # country = params[:country] if params[:country].present?
33
+ # region = state || country || 'US'
34
+ #
35
+ # ...becomes:
36
+ #
37
+ # region = params[:state].presence || params[:country].presence || 'US'
38
+ def presence
39
+ self if present?
40
+ end
41
+ end
42
+
43
+ class NilClass
44
+ # +nil+ is blank:
45
+ #
46
+ # nil.blank? # => true
47
+ def blank?
48
+ true
49
+ end
50
+ end
51
+
52
+ class FalseClass
53
+ # +false+ is blank:
54
+ #
55
+ # false.blank? # => true
56
+ def blank?
57
+ true
58
+ end
59
+ end
60
+
61
+ class TrueClass
62
+ # +true+ is not blank:
63
+ #
64
+ # true.blank? # => false
65
+ def blank?
66
+ false
67
+ end
68
+ end
69
+
70
+ class Array
71
+ # An array is blank if it's empty:
72
+ #
73
+ # [].blank? # => true
74
+ # [1,2,3].blank? # => false
75
+ alias_method :blank?, :empty?
76
+ end
77
+
78
+ class Hash
79
+ # A hash is blank if it's empty:
80
+ #
81
+ # {}.blank? # => true
82
+ # { key: 'value' }.blank? # => false
83
+ alias_method :blank?, :empty?
84
+ end
85
+
86
+ class String
87
+ # A string is blank if it's empty or contains whitespaces only:
88
+ #
89
+ # ''.blank? # => true
90
+ # ' '.blank? # => true
91
+ # ' '.blank? # => true
92
+ # ' something here '.blank? # => false
93
+ def blank?
94
+ self !~ /[^[:space:]]/
95
+ end
96
+ end
97
+
98
+ class Numeric #:nodoc:
99
+ # No number is blank:
100
+ #
101
+ # 1.blank? # => false
102
+ # 0.blank? # => false
103
+ def blank?
104
+ false
105
+ end
106
+ end
@@ -0,0 +1 @@
1
+ require_relative 'object/blank'
@@ -0,0 +1,5 @@
1
+ module Buff
2
+ module Extensions
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Buff
2
+ module Extensions
3
+ require_relative 'extensions/version'
4
+ end
5
+ end
6
+
7
+ require_relative 'extensions/boolean'
8
+ require_relative 'extensions/hash'
9
+ require_relative 'extensions/object'
@@ -0,0 +1 @@
1
+ require_relative 'buff/extensions'
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+
3
+ describe Buff::Extensions::DottedPaths do
4
+ describe "ClassMethods" do
5
+ subject { Hash }
6
+
7
+ describe "::from_dotted_path" do
8
+ it "returns a new Hash" do
9
+ expect(subject.from_dotted_path("deep.nested.item")).to be_a(Hash)
10
+ end
11
+
12
+ it "returns a hash containing the nested keys" do
13
+ obj = subject.from_dotted_path("deep.nested.item")
14
+
15
+ expect(obj).to have_key("deep")
16
+ expect(obj["deep"]).to have_key("nested")
17
+ expect(obj["deep"]["nested"]).to have_key("item")
18
+ end
19
+
20
+ it "sets a nil value for the deepest nested item" do
21
+ obj = subject.from_dotted_path("deep.nested.item")
22
+
23
+ expect(obj["deep"]["nested"]["item"]).to be_nil
24
+ end
25
+
26
+ it "handles a symbol as the dotted path" do
27
+ obj = subject.from_dotted_path(:"a.b.c", "value")
28
+
29
+ expect(obj["a"]["b"]["c"]).to eql("value")
30
+ end
31
+
32
+ context "when given a seed value" do
33
+ it "sets the value of the deepest nested item to the seed" do
34
+ obj = subject.from_dotted_path("deep.nested.item", "seeded_value")
35
+
36
+ expect(obj["deep"]["nested"]["item"]).to eql("seeded_value")
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ subject { Hash.new }
43
+
44
+ describe "#dig" do
45
+ context "when the Hash contains the nested path" do
46
+ subject do
47
+ {
48
+ "we" => {
49
+ "found" => {
50
+ "something" => true
51
+ }
52
+ }
53
+ }
54
+ end
55
+
56
+ it "returns the value at the dotted path" do
57
+ expect(subject.dig("we.found.something")).to eql(true)
58
+ end
59
+ end
60
+
61
+ context "when the Hash does not contain the nested path" do
62
+ it "returns a nil value" do
63
+ expect(subject.dig("nothing.is.here")).to be_nil
64
+ end
65
+ end
66
+
67
+ context "when the Hash contains symbols for keys" do
68
+ subject do
69
+ {
70
+ we: {
71
+ found: {
72
+ something: :symbol_value
73
+ }
74
+ }
75
+ }
76
+ end
77
+
78
+ it "returns the value at the dotted path" do
79
+ expect(subject.dig("we.found.something")).to eql(:symbol_value)
80
+ end
81
+ end
82
+
83
+ it "returns nil if given a blank string" do
84
+ expect(subject.dig("")).to be_nil
85
+ end
86
+
87
+ it "returns 'false' nested values as 'false' and not 'nil'" do
88
+ hash = {
89
+ "ssl" => {
90
+ "verify" => false
91
+ }
92
+ }
93
+
94
+ expect(hash.dig('ssl.verify')).to eql(false)
95
+ end
96
+ end
97
+
98
+ describe "#dotted_paths" do
99
+ it "returns an array" do
100
+ expect(subject.dotted_paths).to be_a(Array)
101
+ end
102
+
103
+ context "given a hash with only top level keys" do
104
+ subject do
105
+ {
106
+ "one" => "val",
107
+ "two" => "val"
108
+ }
109
+ end
110
+
111
+ it "returns an array of the top level keys as strings" do
112
+ expect(subject.dotted_paths).to eql(["one", "two"])
113
+ end
114
+ end
115
+
116
+ context "given a hash with empty hashes as values" do
117
+ subject do
118
+ {
119
+ "one" => Hash.new,
120
+ "two" => Hash.new
121
+ }
122
+ end
123
+
124
+ it "returns an array of the top level keys as strings" do
125
+ expect(subject.dotted_paths).to eql(["one", "two"])
126
+ end
127
+ end
128
+
129
+ context "given a hash with nested keys" do
130
+ subject do
131
+ {
132
+ "one" => {
133
+ "nested" => {
134
+ "attribute" => "hello"
135
+ }
136
+ },
137
+ "two" => {
138
+ "nested" => {
139
+ "attribute" => "other_hello",
140
+ "other_attr" => "world"
141
+ }
142
+ }
143
+ }
144
+ end
145
+
146
+ it "returns an array of dotted paths including the nested Hash keys" do
147
+ expect(subject.dotted_paths).to eql(["one.nested.attribute", "two.nested.attribute", "two.nested.other_attr"])
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,27 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'buff/ruby_engine'
5
+
6
+ def setup_rspec
7
+ RSpec.configure do |config|
8
+ config.expect_with :rspec do |c|
9
+ c.syntax = :expect
10
+ end
11
+
12
+ config.mock_with :rspec
13
+ config.treat_symbols_as_metadata_keys_with_true_values = true
14
+ config.filter_run focus: true
15
+ config.run_all_when_everything_filtered = true
16
+ end
17
+ end
18
+
19
+ if Buff::RubyEngine.jruby?
20
+ require 'buff/extensions'
21
+ setup_rspec
22
+ else
23
+ require 'spork'
24
+
25
+ Spork.prefork { setup_rspec }
26
+ Spork.each_run { require 'buff/extensions' }
27
+ end
metadata ADDED
@@ -0,0 +1,233 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: buff-extensions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jamie Winsor
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: buff-ruby_engine
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.1'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: thor
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.18.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.18.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: fuubar
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: guard
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: guard-rspec
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: guard-spork
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: spork
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ description: Extensions to Core Ruby classes
175
+ email:
176
+ - reset@riotgames.com
177
+ executables: []
178
+ extensions: []
179
+ extra_rdoc_files: []
180
+ files:
181
+ - .gitignore
182
+ - .ruby-version
183
+ - .travis.yml
184
+ - CONTRIBUTING.md
185
+ - Gemfile
186
+ - Guardfile
187
+ - LICENSE
188
+ - README.md
189
+ - Thorfile
190
+ - buff-extensions.gemspec
191
+ - lib/buff-extensions.rb
192
+ - lib/buff/extensions.rb
193
+ - lib/buff/extensions/boolean.rb
194
+ - lib/buff/extensions/hash.rb
195
+ - lib/buff/extensions/hash/dotted_paths.rb
196
+ - lib/buff/extensions/hash/key_transforms.rb
197
+ - lib/buff/extensions/hash/reverse_merge.rb
198
+ - lib/buff/extensions/object.rb
199
+ - lib/buff/extensions/object/blank.rb
200
+ - lib/buff/extensions/version.rb
201
+ - spec/buff/extensions/hash/dotted_paths_spec.rb
202
+ - spec/spec_helper.rb
203
+ homepage: https://github.com/RiotGames/buff-extensions
204
+ licenses:
205
+ - Apache 2.0
206
+ post_install_message:
207
+ rdoc_options: []
208
+ require_paths:
209
+ - lib
210
+ required_ruby_version: !ruby/object:Gem::Requirement
211
+ none: false
212
+ requirements:
213
+ - - ! '>='
214
+ - !ruby/object:Gem::Version
215
+ version: 1.9.2
216
+ required_rubygems_version: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ! '>='
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ segments:
223
+ - 0
224
+ hash: -4518863559578760213
225
+ requirements: []
226
+ rubyforge_project:
227
+ rubygems_version: 1.8.23
228
+ signing_key:
229
+ specification_version: 3
230
+ summary: Extensions to Core Ruby classes
231
+ test_files:
232
+ - spec/buff/extensions/hash/dotted_paths_spec.rb
233
+ - spec/spec_helper.rb