Giter Site home page Giter Site logo

Comments (8)

seuros avatar seuros commented on August 12, 2024 1

I just commented on the PR. @elShiaLabeouf Just do it

from representable.

elShiaLabeouf avatar elShiaLabeouf commented on August 12, 2024 1

Nothing is impossible haha

from representable.

apotonick avatar apotonick commented on August 12, 2024

Hey @elShiaLabeouf, thanks for your kind words! It means a lot to us knowing our tools are helpful to people!

What I am wondering is, what is the matter with the original implementation? What exactly wasn't working for you? We might have missed something, I don't remember ever anyone using the object transformation, so I'm happy you took over!

from representable.

elShiaLabeouf avatar elShiaLabeouf commented on August 12, 2024

Thanks for a quick response! To explain with a few more details:

What I'm trying to achieve

Let's say I have a Rails model Animal that describes a table animals(id, name, age). And I have AnimalRepresenter:

class AnimalRepresenter < Representable::Decorator
  include Representable::Hash

  property :name, getter: ->(represented:, **) { represented.name.upcase }
  property :age,
  property :is_favorite, getter: ->(options:, **) { options[:current_user].favorite_animals_ids.include?(id) }
end

Normally and habitually I'd represent an AR record like this:
represented = AnimalRepresenter.new(animal).to_hash(current_user: current_user)
and it works. I get a decorated object - a hash - with a new represented["is_favorite"] field and the id value is excluded.
But I wish represented was not a hash but an object with properties accessible via method calls: represented.is_favorite

What I tried

I tried to change include Representable::Hash to include Representable::Object, because their source code seemed similar to me, although the docs didn't mention this feature. But with this code:

require 'representable/object'
class AnimalRepresenter < Representable::Decorator
  include Representable::Object

  property :name, getter: ->(represented:, **) { represented.name.upcase }
  property :age,
  property :is_favorite, getter: ->(options:, **) { options[:current_user].favorite_animals_ids.include?(id) }
end

I'm getting an error in the moment of registering the class:

representable/lib/representable/cached.rb:7:in `block in build_definition': undefined local variable or method `format_engine' for AnimalRepresenter:Class (NameError)

          binding_builder = format_engine::Binding
                            ^^^^^^^^^^^^^

I dug the Internet and the Zulip chat to find an example, but unsuccessfully. I decided to fork the repo and make an attempt to implement the feature. Thankfully, the structure of the gem is flexible and easy to extend. So I added a few changes inspired by the hash implementation and added some tests.

Then I noticed the code in test/examples/object.rb, ran it but it resulted with the same error I had got earlier (undefined format_engine). Then I found test/object_test.rb and figured out that the code for my initial task should look something like that:

require 'representable/object'
module AnimalRepresenter 
  include Representable::Object

  property :name, getter: ->(represented:, **) { represented.name.upcase }
  property :age,
  property :is_favorite, getter: ->(options:, **) { options[:current_user].favorite_animals_ids.include?(id) }
end

and with usage like this: AnimalRepresenterModule.prepare(animal).to_object(current_user: current_user).
The getter: options didn't work, so I had to strictly follow the style from the spec: instance: ->(options) { options[:fragment].name.upcase!; options[:fragment] } . To be honest, it looks greek to me.

What I achieved

With the changes from my PR, the line from my initial goal now works: represented = AnimalRepresenter.new(animal).to_object(current_user: current_user).
I get a decorated AR record of a Struct form with custom properties and current user context. The format of the method chain is unified with to_hash and to_json, which is well-documented in the docs. I also paid close attention to the memory usage by caching the Struct class on a representer class level. Plus implemented for_collection and wrap: option.

A brief example of the output from my console:

3.1.0 :009 > animal_array = [Animal.new('Shepard',22,'s'),Animal.new('Pickle',12,'c'),Animal.new('Rodgers',55,'e')]
 => 
[#<Animal:0x00007feaab58a6b8 @age=22, @name="Shepard", @species="s">,
...                                                            
3.1.0 :010 > array_repr = AnimalRepresenter.for_collection.new(animal_array).to_object(wrap: "wrapper")
 => #<struct  wrapper=[#<struct  wrapper=#<struct  name="SHEPARD", age=22>>, #<struct  wrapper=#<struct  name="PICKLE", age=12>>, #<struct  wrapper=#<struct  name="RODGERS", age=55... 

from representable.

yogeshjain999 avatar yogeshjain999 commented on August 12, 2024

@elShiaLabeouf IMO, the to_object method is intended to fill up an object of the same instance and not any other due to it's nature i.e. decorate given object as something else but with a same class.

In your case where you want to access keys of an output hash as a method, could you pass it to OpenStruct for simple method access or Mash if you want nested method access ?

from representable.

apotonick avatar apotonick commented on August 12, 2024

@yogeshjain999 Hm, I kind of had the same in mind what @elShiaLabeouf is asking for. If I remember correctly, the object strategy was meant for nested objects. The OpenStruct approach would only work for one level. To me it sounds like a reasonable approach to make to_object work.

from representable.

elShiaLabeouf avatar elShiaLabeouf commented on August 12, 2024

In your case where you want to access keys of an output hash as a method, could you pass it to OpenStruct for simple method access or Mash if you want nested method access ?

Hi @yogeshjain999 ! That's, for sure, one of workarounds to my needs. But if I did so, I presume, the usage of memory would be inefficient since I'd create a hash first and only then convert it to OpenStruct or Hashie resulting in 2x time and resources needed.

Meanwhile, with my approach we directly create a Struct with no middle-man. In fact, Struct is a structure with high performance - 3 to 50 times faster than OpenStruct (benchmark1, benchmark2). So I believe the feature is worth the hustle :)

from representable.

elShiaLabeouf avatar elShiaLabeouf commented on August 12, 2024

@apotonick thank you for having an understanding of the subject! I'd be happy to see it in master!

I have changed the test according to you suggestion. Is there anything else needed to have it merged?

from representable.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.