https://github.com/imdrasil/jennifer_twin
Jennifer presenter library
https://github.com/imdrasil/jennifer_twin
cloner crystal-language jennifer presenter
Last synced: 8 months ago
JSON representation
Jennifer presenter library
- Host: GitHub
- URL: https://github.com/imdrasil/jennifer_twin
- Owner: imdrasil
- License: mit
- Created: 2019-10-29T15:28:00.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2020-07-03T07:49:44.000Z (over 5 years ago)
- Last Synced: 2025-02-05T21:27:38.145Z (10 months ago)
- Topics: cloner, crystal-language, jennifer, presenter
- Language: Crystal
- Homepage:
- Size: 10.7 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# JenniferTwin [](https://github.com/imdrasil/jennifer_twin/releases)
Super simple library to dump/load [Jennifer](https://github.com/imdrasil/jennifer.cr) model attributes to plain class instance to be able to integrate it with any kind of hidden attributes.
## Installation
1. Add the dependency to your `shard.yml`:
```yaml
dependencies:
jennifer_twin:
github: imdrasil/jennifer_twin
version: 0.1.1
```
2. Run `shards install`
## Usage
Jennifer generates some amount of hidden attributes for a mode to be able to track whether attribute has been changed, relation load state or just a collection, etc. For some tasks you would like to have an instance containing only model attributes or it's subset. One of the most popular example - `JSON::Serializable`. Therefor JenniferTwin copies all data from original instance and store them.
> If you trying to solve issue of model serialization to JSON - take a look at [Serializer](https://github.com/imdrasil/serializer).
To create a **twin** include `JenniferTwin` and call `.map_fields` macro:
```crystal
require "jennifer_twin"
class UserTwin
include JenniferTwin
map_fields User
end
```
### Mapping
`.map_fields` macro generates only 3 things:
- getters for all fields named after model's ones (unless other name is specified)
- initializer accepting model instance to copy
- `#to_model` method to create a model instance from it's fields
```crystal
user = User.all.first
user_twin = UserTwin.new(user)
user_twin.to_model # => User
```
As a 2nd argument macro accepts named tuple or symbol-based hash of field options. Supported options are:
- `:ignore` - if set to `true` ignores specified field
- `:key` - defines attribute with the specified value
- `:annotations` - adds annotations above field setter
Let's take a look at more descriptive example:
```crystal
class User < Jennifer::Model::Base
mapping(
id: Primary32,
name: String?,
age: Int32?,
password_hash: String?
)
end
class UserTwin
include JenniferTwin
include JSON::Serializable
map_fields(User, {
age: { annotations: [@[JSON::Field(emit_null: true)]] }
name: { key: :full_name },
password_hash: { ignore: true }
})
setter full_name
end
user = User.all.first # ">
user_twin = UserTwin.new(user) #
user_twin.to_json # => %({"id":1,"full_name":"User 8","age":null})
user_twin.full_name = "New Name"
user_twin.to_modal #
```
Also you can add additional custom logic to generated initializer passing a block to the macro call. To access model instance use `record` variable name.
```crystal
class UserTwin
include JenniferTwin
getter full_name : String
map_fields(User) do
@full_name = "#{record.name} Snow"
end
end
```
## Contributing
1. Fork it ()
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request
## Contributors
- [Roman Kalnytskyi](https://github.com/imdrasil) - creator and maintainer