diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..6c8a6a7 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,23 @@ +name: Publish Gem +on: + release: + types: + - "created" + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Publish to RubyGems + run: | + mkdir -p $HOME/.gem + touch $HOME/.gem/credentials + chmod 0600 $HOME/.gem/credentials + printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials + gem build hash_kit.gemspec + gem push hash_kit-*.gem + env: + GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}" diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml new file mode 100644 index 0000000..2392292 --- /dev/null +++ b/.github/workflows/rspec.yml @@ -0,0 +1,26 @@ +name: RSpec +on: + - push + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Run tests + run: | + docker-compose up -d + docker exec gem_test_runner bash -c "cd gem_src && bundle install && bundle exec rspec" + + - name: Code Coverage + uses: paambaati/codeclimate-action@v5.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + with: + debug: true + coverageLocations: | + ${{github.workspace}}/coverage/coverage.json:simplecov + prefix: /gem_src + verifyDownload: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ade1ea8..0000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: ruby -rvm: - - 2.3.5 -cache: bundler -before_script: - - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 - > ./cc-test-reporter - - chmod +x ./cc-test-reporter - - "./cc-test-reporter before-build" -after_script: - - "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT" -deploy: - provider: rubygems - api_key: - secure: YymT9pXiLoxk3ceH7SHHPXgxAZc1Hu2HIBp8saryrOdhb0RZ1yYTyG0lIDs30YG85UCxVMN9rwNZrJOTE4GsZNBuTubEK+k9f701pvP6hnmAtUUUt1QwAMi9sz5IKURk1SPI7R/iRTkOcCyM6mhKSC/ItjQfuLsWOCE8snugzKi0cQC3vSonIBal5iJjgeYZkuncZOJcYSyuIfbQaZBBMu7uBGQrykg8fLWX9Sreh9KmFRb9A3FiuH0kroQCrivl/d/X7u4a3WmFXR0Bqj39+C2B4LRuUJ37PHkXgogvpgNyeR/+t4kTWfv96aa3NirxaFc3LB0Zl9ZdEBrNURN+awLmyBt8WmI25NahydGsZMuwWMMXhjx1NWfYGdI53ZAwA8fOsBASqntvtkAWLSpr8Lekv3S844545zHtqeYtYY1egWZ/aHwAckkfRoKJOAyStrN59DHKquJPRdhMEPKM23YwtUrXmjoJ+B/KC/Z6bFiWnDvq5V7FMt3twGmwabHGD+cSglTCdHbpEEbfZYV24NBBclzXhRtAgVUG3obcfJvKPY/f889JlIpWzRdxu74G8K9uxq3ku21EIfWIMKv3Nx4yPyKDdu60RbkUyq7VwvWyO7WgBhU+Vh1pVqMVAe4EErJTqMCXlJulzy8oE3IOhB1oUHyfxTE+dimwX6je4Qc= - gem: hash_kit - on: - tags: true - condition: "$TRAVIS_RUBY_VERSION == 2.3.5" - repo: Sage/class_kit -env: - global: - secure: lI5jMmJJuZm3Z+MHpPxD+85LsGbtevjyVvU0HCMqHol16eXLqUcMFNM13r/loYExNHKB4jMPECOXcgdY5vYlMuLb7vWWQdvb9gwGodkibtqQk069d4UapMiBXzzEddE/Mm0q7dur1MBgwBMhES6a9WJhJneYCd0qeWwgB0KrkjAspfvRsFJQ8euQ8tD5cjzrFE4UL/lIPrnTNEuurGZz4Zmu06bD1et4nRannC7Ms0BsOUfZWsjKsBCZuS+ap1d1J9G+6QN8pnGfwN9W/+bYuJ/B9zMjGIGH/NyGg/uS68eX/hFk5XReAnS9RIlY8Lfo3SALUlZ+Sq3zjTctlmde+yRpHObRGR/QXX4zlZ/php/lrurYmZqMQxHvHPoF9TSliJzCGzIEBACcyX8rAFhtgyRiEJ3hNd6X1Xf/qOe9j+4/PseGQYWgP9wSaLX5sT3BLiEKTjl4V+eFT+MK8LFmdIfgbnaNpb9EnNVvEZwQpE3SXE3BoBVwkkEPbhwHpx2uy3a23Y4vsp0Jo4+lWkTG8YkZGz2+L62pOLU803SktN4wbVSA4kdK6VXGW1wzt2LH8CWlbWaLvbNczWCc+xU8QqBqjvjSQGdgDGISLCZxz7gHrT2g+cHj2Qd6BdMX3uHudXQvwQdIOmAeshiz4qfnbup7k40fab7jHuL62Icibss= diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1816492 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +services: + gem_test_runner: + image: ruby:2.7.8-bullseye + container_name: gem_test_runner + command: bash -c "while true; do echo 'Container is running...'; sleep 2; done" + volumes: + - ./:/gem_src diff --git a/hash_kit.gemspec b/hash_kit.gemspec index 2647fc1..bc7b4cc 100644 --- a/hash_kit.gemspec +++ b/hash_kit.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'hash_kit/version' @@ -13,14 +15,14 @@ Gem::Specification.new do |spec| spec.homepage = 'https://github.com/sage/hash_kit' spec.license = 'MIT' - spec.files = Dir.glob("{bin,lib}/**/**/**") + spec.files = Dir.glob('{bin,lib}/**/**/**') spec.bindir = 'exe' spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] - spec.add_development_dependency 'bundler', '~> 1.11' + spec.add_development_dependency 'bundler' spec.add_development_dependency 'pry' - spec.add_development_dependency 'rake', '~> 10.0' + spec.add_development_dependency 'rake' spec.add_development_dependency 'rspec' - spec.add_development_dependency 'simplecov' + spec.add_development_dependency 'simplecov', '~> 0.21' end diff --git a/lib/hash_kit/helper.rb b/lib/hash_kit/helper.rb index 68bbcc6..5ccf910 100644 --- a/lib/hash_kit/helper.rb +++ b/lib/hash_kit/helper.rb @@ -1,13 +1,15 @@ +# frozen_string_literal: true + module HashKit + # Hash kit Helper class class Helper - - #This method is called to make a hash allow indifferent access (it will accept both strings & symbols for a valid key). + # This method is called to make a hash allow indifferent access (it will + # accept both strings & symbols for a valid key). def indifferent!(hash) - unless hash.is_a?(Hash) - return - end + return unless hash.is_a?(Hash) - #set the default proc to allow the key to be either string or symbol if a matching key is found. + # Set the default proc to allow the key to be either string or symbol if + # a matching key is found. hash.default_proc = proc do |h, k| if h.key?(k.to_s) h[k.to_s] @@ -18,9 +20,9 @@ def indifferent!(hash) end end - #recursively process any child hashes + # Recursively process any child hashes hash.each do |key,value| - if hash[key] != nil + unless hash[key].nil? if hash[key].is_a?(Hash) indifferent!(hash[key]) elsif hash[key].is_a?(Array) @@ -33,9 +35,7 @@ def indifferent!(hash) end def indifferent_array!(array) - unless array.is_a?(Array) - return - end + return unless array.is_a?(Array) array.each do |i| if i.is_a?(Hash) @@ -46,14 +46,16 @@ def indifferent_array!(array) end end - #This method is called to convert all the keys of a hash into symbols to allow consistent usage of hashes within your Ruby application. + # This method is called to convert all the keys of a hash into symbols to + # allow consistent usage of hashes within your Ruby application. def symbolize(hash) {}.tap do |h| hash.each { |key, value| h[key.to_sym] = map_value_symbol(value) } end end - #This method is called to convert all the keys of a hash into strings to allow consistent usage of hashes within your Ruby application. + # This method is called to convert all the keys of a hash into strings to + # allow consistent usage of hashes within your Ruby application. def stringify(hash) {}.tap do |h| hash.each { |key, value| h[key.to_s] = map_value_string(value) } @@ -73,18 +75,22 @@ def to_hash(obj) hash end - def from_hash(hash, klass, transforms = []) + # Return an object of type klass from the values in the given hash + # + # @param [Hash] hash + # @param [Class] klass + # @param [Array] transforms + # @return [Object] + def from_hash(hash, klass, transforms = []) obj = klass.new - if hash ==nil || hash == {} - return obj - end + return obj if hash.nil? || hash.empty? + raise ArgumentError, "#{hash.inspect} is not a hash" unless hash.is_a?(Hash) + + hash.each do |k, v| + next unless obj.respond_to?(k) - hash.each do |k,v| - if !obj.respond_to?(k) - next - end transform = transforms.detect { |t| t.key.to_sym == k.to_sym } - if transform != nil + if !transform.nil? if v.is_a?(Hash) child = from_hash(v, transform.klass, transforms) obj.instance_variable_set("@#{k}", child) @@ -98,7 +104,8 @@ def from_hash(hash, klass, transforms = []) obj.instance_variable_set("@#{k}", v) end end - return obj + + obj end private diff --git a/script/docker-compose.yml b/script/docker-compose.yml deleted file mode 100644 index 763bf2f..0000000 --- a/script/docker-compose.yml +++ /dev/null @@ -1,6 +0,0 @@ -gem_test_runner: - image: codeguru/ruby:2.3.1-alpine-3.4 - container_name: gem_test_runner - command: bash -c "while true; do echo 'Container is running...'; sleep 2; done" - volumes: - - ../:/gem_src \ No newline at end of file diff --git a/spec/hash_kit/helper_spec.rb b/spec/hash_kit/helper_spec.rb index 365db05..8246d72 100644 --- a/spec/hash_kit/helper_spec.rb +++ b/spec/hash_kit/helper_spec.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe HashKit::Helper do describe '#symbolize' do - context 'when a single layer hash with string keys is specified' do let(:hash) { { 'key1' => 'value1', 'key2' => 'value2' } } @@ -64,7 +65,6 @@ end describe '#stringify' do - context 'when a single layer hash with symbol keys is specified' do let(:hash) { { :key1 => 'value1', :key2 => 'value2' } } @@ -122,11 +122,9 @@ expect(new_hash['key3'][1].has_key?(:key4)).to be false end end - end describe '#to_hash' do - let(:key1) do { key1: 'value1' } end @@ -195,7 +193,7 @@ end [ - "string" , + 'string' , 101 , 1.01 , Time.now , @@ -237,36 +235,35 @@ end describe '#from_hash' do - let(:child_hash) do { - text: 'abc', - numeric: 5, - time: Time.now, - invalid_key: 5, - bool: true + text: 'abc', + numeric: 5, + time: Time.now, + invalid_key: 5, + bool: true } end let(:parent_hash) do { - text: 'abc', - numeric: 5, - time: Time.now, - entity: child_hash, - entity_array: [child_hash, child_hash], - invalid_key: 5, - bool: true + text: 'abc', + numeric: 5, + time: Time.now, + entity: child_hash, + entity_array: [child_hash, child_hash], + invalid_key: 5, + bool: true } end let(:string_hash) do { - 'text' => 'abc', - 'numeric' => 5, - 'time' => Time.now, - 'invalid_key' => 5, - 'bool' => true + 'text' => 'abc', + 'numeric' => 5, + 'time' => Time.now, + 'invalid_key' => 5, + 'bool' => true } end @@ -337,6 +334,12 @@ expect(obj.entity_array[1]).to be_a(TestEntity) end end + + context 'when hash is not a hash' do + it 'raises an ArgumentError' do + expect { subject.from_hash('Not a hash', TestEntity, transforms) }.to raise_error(ArgumentError) + end + end end describe '#indifferent' do @@ -356,18 +359,22 @@ } } end + it 'should allow access to a string key from a symbol' do subject.indifferent!(hash) expect(hash[:key1]).to eq 'value1' end + it 'should allow access to a symbol key from a string' do subject.indifferent!(hash) expect(hash['key2']).to eq 'value2' end + it 'should allow indifferent access to a key within an array' do subject.indifferent!(hash) expect(hash[:key3][0]['key4']).to eq 'value4' end + it 'should allow indifferent access to a key within an nested hash' do subject.indifferent!(hash) expect(hash[:key6]['key7']).to eq 'value7' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 78109aa..8f1f47c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,10 @@ +# frozen_string_literal: true + require 'simplecov' +require 'simplecov_json_formatter' + +SimpleCov.formatter = SimpleCov::Formatter::JSONFormatter + SimpleCov.start do add_filter 'spec/' end