Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Transform complex JSON data into custom Ruby objects

License

NotificationsYou must be signed in to change notification settings

jessedoyle/shrink_wrap

Repository files navigation

What is Shrink::Wrap?

Shrink::Wrap is a dead-simple framework to manipulate and map JSON data to Ruby object instances.

Basic Example

Imagine a JSON structure such as:

{"name":"Milky Way","age":"13510000000","solarSystems": [    {"name":"Sol","age":"4571000000","planets": [        {"name":"mercury"        },        {"name":"venus"        },        {"name":"earth"        }      ]    }  ]}

With Shrink::Wrap, you'd be able to map the JSON data to Ruby instances as simply as:

data=JSON.parse(File.read('galaxy.json'))Galaxy.shrink_wrap(data)# => #<Galaxy:0x007fec71254828# @age=13510000000,# @name="Milky Way",# @solar_systems=#  [#<SolarSystem:0x007fec71254850#    @age=4571000000,#    @name="Sol",#    @planets=#     [#<Planet:0x007fec712555c0 @name="MERCURY">,#      #<Planet:0x007fec712553e0 @name="VENUS">,#      #<Planet:0x007fec71255200 @name="EARTH">>]>]>

How Does it Work?

You must include theShrink::Wrap module in your classes to gain access to theshrink_wrap method.

For the example above, the implementation would look like:

require'shrink/wrap'classPlanetincludeShrink::Wraptransform(Shrink::Wrap::Transformer::Symbolize)translate(name:{from::name})coerce(name:->(v){v.upcase})attr_accessor:namedefinitialize(opts={})self.name=opts.fetch(:name)endendclassSolarSystemincludeShrink::Wraptransform(Shrink::Wrap::Transformer::Symbolize)translate(name:{from::name},age:{from::age},planets:{from::planets})coerce(age:->(v){v.to_i},planets:Array[Planet])attr_accessor:name,:age,:planetsdefinitialize(opts={})self.name=opts.fetch(:name)self.age=opts.fetch(:age)self.planets=opts.fetch(:planets)endendclassGalaxyincludeShrink::Wraptransform(Shrink::Wrap::Transformer::Symbolize)translate(name:{from::name},age:{from::age},solar_systems:{from::solarSystems})coerce(age:->(v){v.to_i},solar_systems:Array[SolarSystem])attr_accessor:name,:age,:solar_systemsdefinitialize(opts={})self.name=opts.fetch(:name)self.age=opts.fetch(:age)self.solar_systems=opts.fetch(:solar_systems)endend

Order of Operations

Shrink::Wrap operations are always deterministically performed in the following order:

  1. transform
  2. translate
  3. coerce

Shrink::Wrap will call theinitialize method with the data after all operations have been completed.

Transform

Thetransform operation accepts a transformation class as well as an options hash as parameters.

The transformation class is any Ruby class that inherits fromShrink::Wrap::Transformer::Base.

The class must define atransform(data = {}) method that returns the data after transformations are applied.

You can chain transformers together by callingtransform multiple times in your class. Transformers are always executed sequentially.

You can create your own transformer as such:

classFilterEmpty <Shrink::Wrap::Transformer::Basedeftransform(opts={})data.each_with_object({})do |(key,value),memo|memo[key]=valueunlessvalue.empty?endendend

Built In Transformers

Shrink::Wrap provides a few built-in transformer classes for use with common transformation patterns.

Shrink::Wrap::Transformer::Symbolize

In Ruby, it's very common to convert Hash keys to Symbol instances.

The Symbolize transformer works similar to ActiveSupport'sdeep_symbolize_keys method, but it is also able to traverse nested data structures (Array,Enumerable) and symbolize the keys of any nested elements as well.

The Symbolize transformer accepts an optionaldepth parameter that defines that maximum depth for symbolization in nested data structures.

Example:

classExampleincludeShrink::Wraptransform(Shrink::Wrap::Transformer::Symbolize,depth:2)translate_allattr_accessor:datadefinitialize(data)self.data=dataendenddata={'root'=>[{'nested'=>'test'}]}instance=Example.shrink_wrap(data)instance.data# => {:root=>[{:nested=>"test"}]}

Shrink::Wrap::Transformer::CollectionFromKey

Some data Hashes contain keys that contain relevant data for object instances.

The CollectionFromKey transformer accepts a Hash option that contains a key => attribute mapping.

The transformation then creates an Array of elements taken from the key argument and merges the key into each element in the collection.

Example:

classExampleincludeShrink::Wraptransform(Shrink::Wrap::Transformer::CollectionFromKey,weekends::day)translate_allattr_accessor:datadefinitialize(data)self.data=dataendenddata={weekends:{saturday:{index:6},sunday:{index:0}}}instance=Example.shrink_wrap(data)instance.data# => {:weekends=>[{:index=>6, :day=>:saturday}, {:index=>0, :day=>:sunday}]}

Translate

Thetranslate operation accepts a Hash that contains key/value pairs that map incoming data to attributes.

You can pass the following parameters for each attribute:

  • from [required]: The input key that the attribute is mapped to.
  • allow_nil [optional]: Iftrue, the mapped value may benil. Whenfalse, raisesKeyError if the mapped value isnil.
  • default [optional]: AProc orLambda that returns a particular value. This argument will be called if the value isnil.

Passing Data During Initialization

By default, any attributes not specified in atranslate call are not passed to the underlying object during initialization.

You can calltranslate_all if you wish to pass all of the data but don't wish to explicitly define the attributes in a correspondingtranslate call.

Coerce

Thecoerce operation accepts a hash of attribute keys and coercion values.

Coercions must be one of the following types:

  • Class: Tries callingClass.shrink_wrap(data),Class.coerce(data), thenClass.new(data), returning the first successful result.
  • Enumerable: Coerces the value into the collection of type defined as the Enumerable elements. The first element of the enumerable must be a class name (eg.Array[MyClass],Hash[MyClass => MyClass]).
  • Lambda/Proc: Coerces the value by calling theProc with the value as the only argument.

Contributing

Bug reports and pull requests are welcome on GitHub athttps://github.com/jessedoyle/shrink_wrap.

When making code changes please fork the main repository, create a feature branch and then create a pull request with your change. All code changes must contain adequate test coverage.

This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to theContributor Covenant code of conduct.

License

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

Code of Conduct

Everyone interacting in the ShrinkWrap project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow thecode of conduct.

About

Transform complex JSON data into custom Ruby objects

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp