{"id":15591263,"url":"https://github.com/hopsoft/field_mapper","last_synced_at":"2025-09-12T10:41:53.713Z","repository":{"id":15603288,"uuid":"18339473","full_name":"hopsoft/field_mapper","owner":"hopsoft","description":"Data mapping \u0026 transformation","archived":false,"fork":false,"pushed_at":"2020-08-24T16:55:47.000Z","size":84,"stargazers_count":27,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-13T04:56:30.091Z","etag":null,"topics":["data-conversion","data-transformation","ruby"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hopsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-04-01T18:13:12.000Z","updated_at":"2025-03-19T15:38:12.000Z","dependencies_parsed_at":"2022-09-17T21:55:13.784Z","dependency_job_id":null,"html_url":"https://github.com/hopsoft/field_mapper","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/hopsoft/field_mapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffield_mapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffield_mapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffield_mapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffield_mapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hopsoft","download_url":"https://codeload.github.com/hopsoft/field_mapper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hopsoft%2Ffield_mapper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274799894,"owners_count":25352172,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-12T02:00:09.324Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-conversion","data-transformation","ruby"],"created_at":"2024-10-02T23:40:44.827Z","updated_at":"2025-09-12T10:41:53.667Z","avatar_url":"https://github.com/hopsoft.png","language":"Ruby","readme":"[![Lines of Code](http://img.shields.io/badge/lines_of_code-1012-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)\n[![Build Status](http://img.shields.io/travis/hopsoft/field_mapper.svg?style=flat)](https://travis-ci.org/hopsoft/field_mapper)\n[![Coverage Status](https://img.shields.io/coveralls/hopsoft/field_mapper.svg?style=flat)](https://coveralls.io/r/hopsoft/field_mapper?branch=master)\n\n# FieldMapper\n\n## Data Mapping \u0026 Transformation\n\n### Uses\n\n- Mapping data between 2 or more formats\n- Transforming data with complex rules\n- Defining data standards\n\n### Overview\n\nFieldMapper introduces a new term for a model-like data structure\nto avoid possible confusion with libraries such as ActiveRecord.\n\nThis new term is: **Plat**\n\nA plat defines the following:\n\n- Fields\n- Datatypes\n- Mappings\n- Transformation rules\n\nDatatype declarations exist to support implicit type casting of values.\nThe supported datatypes are:\n\n- String\n- Boolean\n- Time\n- Integer\n- Float\n- Money\n- Plat\n- List (of any listed type)\n\n## Usage\n\n```sh\ngem install field_mapper\n```\n\n```ruby\n# Gemfile\ngem \"field_mapper\"\n```\n\nSuppose we want to perform a mapping between Facebook users \u0026 Twitter users.\n\n1. First we need to define a standard user class.\n\n    ```ruby\n    class StandardUser \u003c FieldMapper::Standard::Plat\n      field :name,        type: String\n      field :screen_name, type: String\n      field :info,        type: String\n      field :website,     type: String\n      field :age,         type: Integer\n\n      # field with allowed values\n      field :gender, type: String do\n        value \"F\"\n        value \"M\"\n      end\n\n      # field with a default value\n      field :net_worth,\n        type: Money,\n        default: 0\n\n      # field that holds a list of plats\n      field :friends,\n        type: FieldMapper::Types::List[StandardUser],\n        default: []\n    end\n    ```\n\n2. Next we define a Facebook user class that maps onto our standard.\n\n    ```ruby\n    class FacebookUser \u003c FieldMapper::Custom::Plat\n      # note that we set the standard\n      set_standard StandardUser\n\n      # fields are mapped to the standard\n      field :name,      standard: :name\n      field :bio,       standard: :info\n      field :website,   standard: :website\n      field :net_worth, standard: :net_worth\n\n      # field with mapped values\n      field :gender,    standard: :gender do\n        value \"female\", standard: \"F\"\n        value \"male\",   standard: \"M\"\n      end\n\n      # some fields don't map to a standard\n      field :birthday, type: Time\n\n      field :friends,\n        standard: :friends,\n        type: FieldMapper::Types::List[FacebookUser], # \u003c- lists must define type even when mapped to a standard\n        default: []\n\n      # field with complex transformation rules\n      field :username,\n        standard: :screen_name,\n        custom_to_standard: -\u003e (value, standard_instance: nil) {\n          # value passed is the custom value\n          # value returned is the standard value\n          \"Facebook:#{value.to_s.strip}\"\n        },\n        standard_to_custom: -\u003e (value, standard_instance: nil) {\n          # value passed is the standard value\n          # value returned is the custom value\n          value.to_s.split(/:/).last\n        }\n    end\n    ```\n\n3. Then we define a Twitter user class that maps onto our standard.\n\n    ```ruby\n    class TwitterUser \u003c FieldMapper::Custom::Plat\n      set_standard StandardUser\n\n      field :name,            standard: :name\n      field :description,     standard: :info\n      field :url,             standard: :website\n      field :followers_count, type: Integer\n\n      field :screen_name,     standard: :screen_name,\n        custom_to_standard: -\u003e (value, standard_instance: nil) {\n          \"Twitter:#{value.to_s.strip}\"\n        },\n        standard_to_custom: -\u003e (value, standard_instance: nil) {\n          value.to_s.split(/:/).last\n        }\n\n      # callback method that runs after tranformation\n      def after_convert(from: nil, to: nil)\n        if from.respond_to? :friends\n          self.followers_count = from.friends.length\n        end\n      end\n    end\n    ```\n\n4. Now we can construct a Facebook user.\n\n    ```ruby\n    zuck = FacebookUser.new(\n      name: \"Mark Zuckerberg\",\n      username: \"zuck\",\n      bio: \"Creator of Facebook\",\n      website: \"http://www.facebook.com/zuck\",\n      gender: \"male\",\n      age: 29,\n      net_worth: \"$29,000,000,000 USD\", # value will be cast to a Money\n      birthday: \"1984-05-14\" # value will be cast to a Time\n    )\n\n    zuck.friends \u003c\u003c FacebookUser.new(name: \"Priscilla Chan\")\n    ```\n\n5. We can also transform our Facebook user to a standard user.\n\n    ```ruby\n    converter = FieldMapper::Custom::Converter.new(zuck)\n    standard_zuck = converter.convert_to_standard\n    ```\n\n6. We can also transform our Facebook user to a Twitter user.\n\n    ```ruby\n    converter = FieldMapper::Custom::Converter.new(zuck)\n    twitter_zuck = converter.convert_to(TwitterUser)\n    ```\n\n7. We can transform a standard user into both a Facebook \u0026 Twitter user.\n\n    ```ruby\n    converter = FieldMapper::Standard::Converter.new(standard_zuck)\n    zuck_from_standard = converter.convert_to(FacebookUser)\n    twitter_zuck_from_standard = converter.convert_to(TwitterUser)\n    ```\n\n8. We can emit our objects as a Hash.\n\n    ```ruby\n    zuck_hash = zuck.to_hash\n    {\n      \"_node_id\"  =\u003e 70260402777020,\n      \"_flat\"     =\u003e false,\n      \"name\"      =\u003e \"Mark Zuckerberg\",\n      \"username\"  =\u003e \"zuck\",\n      \"bio\"       =\u003e \"Creator of Facebook\",\n      \"website\"   =\u003e \"http://www.facebook.com/zuck\",\n      \"gender\"    =\u003e \"male\",\n      \"net_worth\" =\u003e \"$29,000,000,000.00 USD\",\n      \"friends\"   =\u003e [\n        {\n          \"_node_id\"  =\u003e 70260401841760,\n          \"_flat\"     =\u003e false,\n          \"name\"      =\u003e \"Priscilla Chan\",\n          \"username\"  =\u003e nil,\n          \"bio\"       =\u003e nil,\n          \"website\"   =\u003e nil,\n          \"gender\"    =\u003e nil,\n          \"net_worth\" =\u003e nil,\n          \"friends\"   =\u003e [],\n          \"birthday\"  =\u003e nil\n        }\n      ],\n      \"birthday\" =\u003e \"1984-05-14T06:00:00Z\"\n    }\n\n    zuck_flat_hash = zuck.to_hash(flatten: true)\n    {\n      \"_node_id\"  =\u003e 70260402777020,\n      \"_flat\"     =\u003e true,\n      \"name\"      =\u003e \"Mark Zuckerberg\",\n      \"username\"  =\u003e \"zuck\",\n      \"bio\"       =\u003e \"Creator of Facebook\",\n      \"website\"   =\u003e \"http://www.facebook.com/zuck\",\n      \"gender\"    =\u003e \"male\",\n      \"net_worth\" =\u003e \"$29,000,000,000.00 USD\",\n      \"friends\"   =\u003e \"[{\\\"_node_id\\\":70260401841760,\\\"_flat\\\":true,\\\"name\\\":\\\"Priscilla Chan\\\",\\\"username\\\":null,\\\"bio\\\":null,\\\"website\\\":null,\\\"gender\\\":null,\\\"net_worth\\\":null,\\\"friends\\\":[],\\\"birthday\\\":null}]\",\n      \"birthday\"  =\u003e \"1984-05-14T06:00:00Z\"\n    }\n    ```\n\n9. We can also reconstruct instances from a Hash.\n\n    ```ruby\n    zuck_from_hash = FacebookUser.new(zuck_hash)\n    zuck_from_flat_hash = FacebookUser.new(zuck_flat_hash)\n    ```\n\nThis is powerful stuff.\nI invite you to play around \u0026 experiment.\nRead through [the tests](https://github.com/hopsoft/field_mapper/tree/master/test) for more detail.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhopsoft%2Ffield_mapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhopsoft%2Ffield_mapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhopsoft%2Ffield_mapper/lists"}