All Projects → arturictus → Hash_map

arturictus / Hash_map

Licence: mit
Nicer way to map your hashes

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Hash map

John
John the Ripper jumbo - advanced offline password cracker, which supports hundreds of hash and cipher types, and runs on many operating systems, CPUs, GPUs, and even some FPGAs
Stars: ✭ 5,656 (+70600%)
Mutual labels:  hash
Robin Hood Hashing
Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20
Stars: ✭ 658 (+8125%)
Mutual labels:  hash
Hashtopolis
A Hashcat wrapper for distributed hashcracking
Stars: ✭ 835 (+10337.5%)
Mutual labels:  hash
Specs
Content-addressed, authenticated, immutable data structures
Stars: ✭ 539 (+6637.5%)
Mutual labels:  hash
Jquery.localscroll
Animated anchor navigation made easy with jQuery
Stars: ✭ 624 (+7700%)
Mutual labels:  hash
Mapper
Mybatis Common Mapper - Easy to use
Stars: ✭ 6,680 (+83400%)
Mutual labels:  mapper
Rxfirebase
Rxjava 2.0 wrapper on Google's Android Firebase library.
Stars: ✭ 509 (+6262.5%)
Mutual labels:  mapper
Jsoo router
A small router to write easily single-page-app in Js_of_ocaml
Stars: ✭ 24 (+200%)
Mutual labels:  hash
P Map
Map over promises concurrently
Stars: ✭ 639 (+7887.5%)
Mutual labels:  mapper
Mappinggenerator
🔄 "AutoMapper" like, Roslyn based, code fix provider that allows to generate mapping code in design time.
Stars: ✭ 831 (+10287.5%)
Mutual labels:  mapper
Name That Hash
🔗 Don't know what type of hash it is? Name That Hash will name that hash type! 🤖 Identify MD5, SHA256 and 3000+ other hashes ☄ Comes with a neat web app 🔥
Stars: ✭ 540 (+6650%)
Mutual labels:  hash
Openhashtab
📝 File hashing and checking shell extension
Stars: ✭ 599 (+7387.5%)
Mutual labels:  hash
Orm
PHP DataMapper, ORM
Stars: ✭ 827 (+10237.5%)
Mutual labels:  mapper
Ethereumjs Util
Project is in active development and has been moved to the EthereumJS monorepo.
Stars: ✭ 534 (+6575%)
Mutual labels:  hash
Vuex Mappers
Component agnostic Vuex mappers
Stars: ✭ 19 (+137.5%)
Mutual labels:  mapper
Pg pathman
Partitioning tool for PostgreSQL
Stars: ✭ 509 (+6262.5%)
Mutual labels:  hash
Free Style
Make CSS easier and more maintainable by using JavaScript
Stars: ✭ 693 (+8562.5%)
Mutual labels:  hash
Performance
In diesem Repository befinden sich Projekte rund um das Thema Performanz.
Stars: ✭ 7 (-12.5%)
Mutual labels:  mapper
Node
Stampery API for NodeJS. Notarize all your data using the blockchain
Stars: ✭ 23 (+187.5%)
Mutual labels:  hash
Hash Set
#️⃣ Set with custom equality comparisons
Stars: ✭ 6 (-25%)
Mutual labels:  hash

HashMap

Build Status Gem Version Code Climate Coverage Status Issue Count

HashMap is a small library that allow you to map hashes with style :). It will remove from your code many of the ugly navigation inside hashes to get your needed hash structure.

Installation

Add this line to your application's Gemfile:

gem 'hash_map'

And then execute:

$ bundle

Or install it yourself as:

$ gem install hash_map

Usage

Your hash:

{
  name: 'Artur',
  first_surname: 'hello',
  second_surname: 'world',
  address: {
    postal_code: 12345,
    country: {
      name: 'Spain',
      language: 'ES'
    }
  },
  email: '[email protected]',
  phone: nil
}

Your beautiful Mapper:

class ProfileMapper < HashMap::Base
  property :first_name, from: :name

  property :last_name do |input|
    "#{input[:first_surname]} #{input[:second_surname]}"
  end

  property :language, from: [:address, :country, :language]

  from_child :address do
    property :code, from: :postal_code
    from_child :country do
      property :country_name, from: :name
    end
  end

  to_child :email do
    property :address, from: :email
    property :type, default: :work
  end

  property :telephone, from: :phone
end

Your wanted hash:

ProfileMapper.map(original)
=> {
  first_name: "Artur",
  last_name: "hello world",
  language: "ES",
  code: 12345,
  country_name: "Spain",
  email: {
    address: "[email protected]",
    type: :work
  },
  telephone: nil
}

IMPORTANT:

  • The output is a Fusu::HashWithIndifferentAccess you can access the values with strings or symbols.
  • The input is transformed as well, that's why you do not need to use strings.

Enjoy!

Examples:

form_child:

{
  passenger_data: {
    traveller_information: {
      passenger: {
        first_name: 'Juanito'
      },
      traveller: {
        surname: 'Perez'
      }
    }
  }
}

class DeepExtraction < HashMap::Base
  from_child :passenger_data, :traveller_information do
    property :firstname, from: [:passenger, :first_name]
    property :lastname, from: [:traveller, :surname]
  end
end

No 'from' key needed:

class Clever < HashMap::Base
  property :name # will get value from the key 'name'
  property :address
end

Properties:

class Properties < HashMap::Base
  properties :name, :address, :house
end

Collections:

You can map collections passing the mapper option, can be another mapper a proc or anything responding to .call with one argument.

class Thing < HashMap::Base
  properties :name, :age
end

class Collections < HashMap::Base
  collection :things, mapper: Thing
  collection :numbers, mapper: proc { |n| n.to_i }
end

The collection method always treats the value as an Array and it always returns an Array. If the value is not an Array it will be wrapped in a new one. If the value is nil it always returns [].

Collections.map({ things: nil})
=> {
    things: []
    numbers: []
}

Collections.map({ numbers: '1'})
=> {
   things: []
   numbers: [1]
}

Options Adding a second argument will make it available with the name options

class UserMapper < HashMap::Base
  properties :name, :lastname
  property :company_name do
    options[:company_name]
  end
end

user = {name: :name, lastname: :lastname}

UserMapper.map(user, company_name: :foo)
#=> {"name"=>:name, "lastname"=>:lastname, "company_name"=>:foo}

Inheritance When inheriting from a Mapper child will inherit the properties

class UserMapper < HashMap::Base
  properties :name, :lastname
end

class AdminMapper < UserMapper
  properties :role, :company
end

original = {
  name: 'John',
  lastname: 'Doe',
  role: 'Admin',
  company: 'ACME'
}

UserMapper.map(original)
#=> { name: 'John', lastname: 'Doe' }

AdminMapper.map(original)
#=> { name: 'John', lastname: 'Doe', role: 'Admin', company: 'ACME' }

Methods:

You can create your helpers in the mapper and call them inside the block

class Methods < HashMap::Base
  property(:common_names) { names }
  property(:date) { |original| parse_date original[:date] }
  property(:class_name) { self.class.name } #=> "Methods"

  def names
    %w(John Morty)
  end

  def parse_date(date)
    date.strftime('%H:%M')
  end
end

Blocks:

In from_child block when you want to get the value with a block the value of the child and original will be yielded in this order: child, original

class Blocks < HashMap::Base
  from_child :address do
    property :street do |address|
      address[:street].upcase
    end
    property :owner do |address, original|
      original[:name]
    end
    from_child :country do
      property :country do |country|
        country[:code].upcase
      end
    end
  end
  property :name do |original|
    original[:name]
  end
end

hash = {
  name: 'name',
  address:{
    street: 'street',
    country:{
      code: 'es'
    }
  }
}

Blocks.map(hash)
# => {"street"=>"STREET", "owner"=>"name", "country"=>"ES", "name"=>"name"}

Middlewares

transforms_output

original = {
  "StatusCode" => 200,
  "ErrorDescription" => nil,
  "Messages" => nil,
  "CompanySettings" => {
    "CompanyIdentity" => {
      "CompanyGuid" => "0A6005FA-161D-4290-BB7D-B21B14313807",
      "PseudoCity" => {
        "Code" => "PARTQ2447"
      }
    },
    "IsCertifyEnabled" => false,
    "IsProfileEnabled" => true,
    "PathMobileConfig" => nil
  }
}

class TransformsOutput < HashMap::Base
  transforms_output  HashMap::UnderscoreKeys
  from_child 'CompanySettings' do
    from_child 'CompanyIdentity' do
      property 'CompanyGuid'
    end
    properties 'IsCertifyEnabled', 'IsProfileEnabled', 'PathMobileConfig'
  end
end

TransformsOutput.call(original)
# => {:company_guid=>"0A6005FA-161D-4290-BB7D-B21B14313807", :is_certify_enabled=>false, :is_profile_enabled=>true, :path_mobile_config=>nil}

Transforms input

original = {
  "StatusCode" => 200,
  "ErrorDescription" => nil,
  "Messages" => nil,
  "CompanySettings" => {
    "CompanyIdentity" => {
      "CompanyGuid" => "0A6005FA-161D-4290-BB7D-B21B14313807",
      "PseudoCity" => {
        "Code" => "PARTQ2447"
      }
    },
    "IsCertifyEnabled" => false,
    "IsProfileEnabled" => true,
    "PathMobileConfig" => nil
  }
}

class TransformsInput < HashMap::Base
  transforms_input  HashMap::UnderscoreKeys
  from_child :company_settings do
    from_child :company_identity do
      property :company_guid
    end
    properties :is_certify_enabled, :is_profile_enabled, :path_mobile_config
  end
end

TransformsInput.call(original)
# => {:company_guid=>"0A6005FA-161D-4290-BB7D-B21B14313807", :is_certify_enabled=>false, :is_profile_enabled=>true, :path_mobile_config=>nil}

After each

class AfterEach < HashMap::Base
  properties :name, :age
  after_each HashMap::BlankToNil, HashMap::StringToBoolean
end

blanks = {
  name: '',
  age: ''
}
booleans = {
  name: 'true',
  age: 'false'
}
AfterEach.call(blanks)
#=> {"name"=>nil, "age"=>nil}

AfterEach.call(booleans)
#=> {"name"=>true, "age"=>false}

only_provided_keys, only_provided_call

class RegularMapper < HashMap::Base
  properties :name, :lastname, :phone
  from_child :address do
    to_child :address do
      properties :street, :number
    end
  end
end
class OnlyProvidedKeysMapper < RegularMapper
  only_provided_keys
end

input = { name: "john", address: {street: "Batu Mejan" }, phone: nil }
RegularMapper.call(input) # => {"name"=>"john", "lastname"=>nil, "phone"=>nil, "address"=>{"street"=>"Batu Mejan", "number"=>nil}}
OnlyProvidedKeysMapper.call(input) # => {"name"=>"john", phone: nil, "address"=>{"street"=>"Batu Mejan"}}

You can use a only_provided_call instead of call if you want to achieve the same result:

RegularMapper.only_provided_call(input) # => {"name"=>"john", phone: nil, "address"=>{"street"=>"Batu Mejan"}}

JSON Adapter

class UserMapper < HashMap::Base
  from_child :user do
    properties :name, :surname
  end
end
json = %Q[{"user":{"name":"John","surname":"Doe"}}]
UserMapper.map(json)
# => {"name"=>"John", "surname"=>"Doe"}

Testing

RSpec

hash_mapped

it do
  output = { name: :hello }
  expect(output).to hash_mapped(:name)
end

from

it do
  original = { first_name: :hello }
  output = { name: :hello }
  expect(output).to hash_mapped(:name).from(original, :first_name)
end

it do
  original = { user: { first_name: :hello } }
  output = { name: :hello }
  expect(output).to hash_mapped(:name).from(original, :user, :first_name)
end

it do
  original = { user: { first_name: :hello } }
  output = { user: { name: :hello } }
  expect(output).to hash_mapped(:user, :name).from(original, :user, :first_name)
end

and_eq

it do
  output = { user: { name: :hello } }
  expect(output).to hash_mapped(:user, :name).and_eq(:hello)
end

Motivation

I got bored of doing this:

# this is a hash from an API
hash = JSON.parse(response, :symbolize_names => true)
# hash = {
#   user: {
#     name: 'John',
#     last_name: 'Doe',
#     telephone: '989898',
#     country: {
#       code: 'es'
#     }
#   }
# }

user_hash = hash[:user]
user = User.new
user.name = user_hash[:name]
user.lastname = user_hash[:last_name]
user.phone = Phone.parse(user_hash[:telephone])
user.country = Country.find_by(code: user_hash[:country][:code])

# boring!!!
# and that's a tiny response

solution:

User.create(MyMapper.map(api_response)) # done

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake rspec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hash_map. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].