Skip to content

Commit fcf985d

Browse files
committed
rename to_object to to_struct
1 parent 061fa0f commit fcf985d

11 files changed

Lines changed: 210 additions & 150 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ To use a specific format, include the corresponding module in your representer a
139139
- `Representable::JSON#to_json`
140140
- `Representable::JSON#to_hash` (provides a hash instead of string)
141141
- `Representable::Hash#to_hash`
142-
- `Representable::Object#to_object` (provides a Struct-based object)
142+
- `Representable::Struct#to_struct` (provides a Struct-based object)
143143
- `Representable::XML#to_xml`
144144
- `Representable::YAML#to_yaml`
145145

lib/representable/hash.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def from_hash(data, options={}, binding_builder=Binding)
3535

3636
def to_hash(options={}, binding_builder=Binding)
3737
hash = create_representation_with({}, options, binding_builder)
38+
3839
return hash if options[:wrap] == false
3940
return hash unless (wrap = options[:wrap] || representation_wrap(options))
4041

lib/representable/object.rb

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
module Representable
55
module Object
6-
autoload :Collection, 'representable/object/collection'
7-
86
def self.included(base)
97
base.class_eval do
108
include Representable
@@ -15,40 +13,17 @@ def self.included(base)
1513

1614

1715
module ClassMethods
18-
def format_engine
19-
Representable::Object
20-
end
21-
2216
def collection_representer_class
2317
Collection
2418
end
25-
26-
def cache_struct
27-
@represented_struct ||= Struct.new(*representable_attrs.keys.map(&:to_sym))
28-
end
29-
30-
def cache_wrapper_struct(wrap:)
31-
struct_name = :"@_wrapper_struct_#{wrap}"
32-
return instance_variable_get(struct_name) if instance_variable_defined?(struct_name)
33-
34-
instance_variable_set(struct_name, Struct.new(wrap))
35-
end
3619
end
3720

3821
def from_object(data, options={}, binding_builder=Binding)
3922
update_properties_from(data, options, binding_builder)
4023
end
4124

4225
def to_object(options={}, binding_builder=Binding)
43-
represented_struct = self.class.cache_struct
44-
45-
object = create_representation_with(represented_struct.new, options, binding_builder)
46-
return object if options[:wrap] == false
47-
return object unless (wrap = options[:wrap] || representation_wrap(options))
48-
49-
wrapper_struct = self.class.cache_wrapper_struct(wrap: wrap.to_sym)
50-
wrapper_struct.new(object)
26+
create_representation_with(nil, options, binding_builder)
5127
end
52-
5328
end
5429
end

lib/representable/object/binding.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ def self.build_for(definition) # TODO: remove default arg.
99
new(definition)
1010
end
1111

12-
def read(struct, as)
13-
fragment = struct.send(as) # :getter? no, that's for parsing!
12+
def read(hash, as)
13+
fragment = hash.send(as) # :getter? no, that's for parsing!
1414

1515
return FragmentNotFound if fragment.nil? and typed?
1616

1717
fragment
1818
end
1919

20-
def write(struct, fragment, as)
21-
struct.send("#{as}=", fragment)
20+
def write(hash, fragment, as)
21+
true
2222
end
2323

2424
def deserialize_method

lib/representable/struct.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
require 'representable'
2+
require 'representable/struct/binding'
3+
4+
module Representable
5+
module Struct
6+
autoload :Collection, 'representable/struct/collection'
7+
8+
def self.included(base)
9+
base.class_eval do
10+
include Representable
11+
extend ClassMethods
12+
register_feature Representable::Struct
13+
end
14+
end
15+
16+
17+
module ClassMethods
18+
def format_engine
19+
Representable::Struct
20+
end
21+
22+
def collection_representer_class
23+
Collection
24+
end
25+
26+
def cache_struct
27+
@represented_struct ||= ::Struct.new(*representable_attrs.keys.map(&:to_sym))
28+
end
29+
30+
def cache_wrapper_struct(wrap:)
31+
struct_name = :"@_wrapper_struct_#{wrap}"
32+
return instance_variable_get(struct_name) if instance_variable_defined?(struct_name)
33+
34+
instance_variable_set(struct_name, ::Struct.new(wrap))
35+
end
36+
end
37+
38+
def to_struct(options={}, binding_builder=Binding)
39+
represented_struct = self.class.cache_struct
40+
41+
object = create_representation_with(represented_struct.new, options, binding_builder)
42+
return object if options[:wrap] == false
43+
return object unless (wrap = options[:wrap] || representation_wrap(options))
44+
45+
wrapper_struct = self.class.cache_wrapper_struct(wrap: wrap.to_sym)
46+
wrapper_struct.new(object)
47+
end
48+
end
49+
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require 'representable/binding'
2+
3+
module Representable
4+
module Struct
5+
class Binding < Representable::Binding
6+
def self.build_for(definition)
7+
return Collection.new(definition) if definition.array?
8+
9+
new(definition)
10+
end
11+
12+
def read(struct, as)
13+
fragment = struct.send(as) # :getter? no, that's for parsing!
14+
15+
return FragmentNotFound if fragment.nil? and typed?
16+
17+
fragment
18+
end
19+
20+
def write(struct, fragment, as)
21+
struct.send("#{as}=", fragment)
22+
end
23+
24+
def serialize_method
25+
:to_struct
26+
end
27+
28+
class Collection < self
29+
include Representable::Binding::Collection
30+
end
31+
end
32+
end
33+
end
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
require 'representable/hash'
22

3-
module Representable::Object
3+
module Representable::Struct
44
module Collection
5-
include Representable::Object
5+
include Representable::Struct
66

77
def self.included(base)
88
base.class_eval do
9-
include Representable::Object
9+
include Representable::Struct
1010
extend ClassMethods
1111
property(:_self, {:collection => true})
1212
end

test/examples/object.rb

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
source = OpenStruct.new(
77
name: "30 Years Live", songs: [
8-
OpenStruct.new(id: 1, title: "Dear Beloved"), OpenStruct.new(id: 2, title: "Fuck Armageddon")
9-
]
8+
OpenStruct.new(id: 1, title: "Dear Beloved"), OpenStruct.new(id: 2, title: "Fuck Armageddon")
9+
]
1010
)
1111

1212
require "representable/object"
@@ -26,30 +26,3 @@ class AlbumRepresenter < Representable::Decorator
2626
target = Album.new
2727

2828
AlbumRepresenter.new(target).from_object(source)
29-
30-
# Representing to_object:
31-
32-
class Animal
33-
attr_accessor :name, :age, :species
34-
def initialize(name, age, species)
35-
@name = name
36-
@age = age
37-
@species = species
38-
end
39-
end
40-
41-
require "representable/object"
42-
43-
class AnimalRepresenter < Representable::Decorator
44-
include Representable::Object
45-
46-
property :name, getter: ->(represented:, **) { represented.name.upcase }
47-
property :age
48-
end
49-
50-
animal = Animal.new('Smokey',12,'c')
51-
animal_repr = AnimalRepresenter.new(animal).to_object(wrap: "wrapper")
52-
53-
animal_array = [Animal.new('Shepard',22,'s'),Animal.new('Pickle',12,'c'),Animal.new('Rodgers',55,'e')]
54-
array_repr = AnimalRepresenter.for_collection.new(animal_array).to_object
55-

test/examples/struct.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
require "representable/struct"
2+
3+
# Representing to_struct:
4+
class Animal
5+
attr_accessor :name, :age, :species
6+
def initialize(name, age, species)
7+
@name = name
8+
@age = age
9+
@species = species
10+
end
11+
end
12+
13+
class AnimalRepresenter < Representable::Decorator
14+
include Representable::Struct
15+
16+
property :name, getter: ->(represented:, **) { represented.name.upcase }
17+
property :age
18+
end
19+
20+
animal = Animal.new('Smokey',12,'c')
21+
animal_repr = AnimalRepresenter.new(animal).to_struct(wrap: "wrapper")
22+
23+
animal_array = [Animal.new('Shepard',22,'s'),Animal.new('Pickle',12,'c'),Animal.new('Rodgers',55,'e')]
24+
array_repr = AnimalRepresenter.for_collection.new(animal_array).to_struct
25+
26+
animal_klass = Struct.new("Animal", :name, :age, :species)
27+
AnimalRepresenter.new(animal_klass.new("qwik", 12, "old")).to_struct(wrap: "wrapper")

test/object_test.rb

Lines changed: 7 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class ObjectTest < MiniTest::Spec
2424
it do
2525
representer.prepare(target).from_object(source)
2626

27-
assert_equal target.title, "The King Is Dead"
28-
assert_equal target.album.name, "RUINER"
29-
assert_equal target.album.songs[0].title, "IN VINO VERITAS II"
27+
assert_equal "The King Is Dead", target.title
28+
assert_equal "RUINER", target.album.name
29+
assert_equal "IN VINO VERITAS II", target.album.songs[0].title
3030
end
3131

3232
# ignore nested object when nil
@@ -51,90 +51,10 @@ class ObjectTest < MiniTest::Spec
5151
end
5252
end
5353

54-
# it do
55-
# representer.prepare(source).to_object
56-
# _(source.album.name).must_equal "Live"
57-
# _(source.album.songs[0].title).must_equal 1
58-
# end
59-
end
60-
end
61-
62-
class ObjectPublicMethodsTest < Minitest::Spec
63-
Song = Struct.new(:title, :album)
64-
Album = Struct.new(:id, :name, :songs, :free_concert_ticket_promo_code)
65-
class AlbumRepresenter < Representable::Decorator
66-
include Representable::Object
67-
property :id
68-
property :name, getter: ->(*) { name.lstrip.strip }
69-
property :cover_png, getter: ->(options:, **) { options[:cover_png] }
70-
collection :songs do
71-
property :title, getter: ->(*) { title.upcase }
72-
property :album, getter: ->(*) { album.upcase }
54+
it do
55+
representer.prepare(source).to_object
56+
_(source.album.name).must_equal "Live"
57+
_(source.album.songs[0].title).must_equal 1
7358
end
7459
end
75-
76-
#---
77-
# to_object
78-
let(:album) { Album.new(1, " Rancid ", [Song.new("In Vino Veritas II", "Rancid"), Song.new("The King Is Dead", "Rancid")], "S3KR3TK0D3") }
79-
let(:cover_png) { "example.com/cover.png" }
80-
it do
81-
represented = AlbumRepresenter.new(album).to_object(cover_png: cover_png)
82-
assert_equal represented.id, album.id
83-
refute_equal represented.name, album.name
84-
assert_equal represented.name, album.name.lstrip.strip
85-
refute_equal represented.songs[0].title, album.songs[0].title
86-
assert_equal represented.songs[0].title, album.songs[0].title.upcase
87-
88-
assert_respond_to album, :free_concert_ticket_promo_code
89-
refute_respond_to represented, :free_concert_ticket_promo_code
90-
91-
assert_equal represented.cover_png, cover_png
92-
end
93-
94-
it do
95-
represented = AlbumRepresenter.new(album).to_object(cover_png: cover_png)
96-
assert_equal represented.id, album.id
97-
refute_equal represented.name, album.name
98-
assert_equal represented.name, album.name.lstrip.strip
99-
refute_equal represented.songs[0].title, album.songs[0].title
100-
assert_equal represented.songs[0].title, album.songs[0].title.upcase
101-
102-
assert_respond_to album, :free_concert_ticket_promo_code
103-
refute_respond_to represented, :free_concert_ticket_promo_code
104-
105-
assert_equal represented.cover_png, cover_png
106-
end
107-
108-
let(:albums) do [
109-
Album.new(1, "Rancid", [Song.new("In Vino Veritas II", "Rancid"), Song.new("The King Is Dead", "Rancid")], "S3KR3TK0D3"),
110-
Album.new(2, "Punk powerhouse", [Song.new("Hard Outside The Box", "Punk powerhous"), Song.new("Wonderful Noise", "Punk powerhous")], "S3KR3TK0D3"),
111-
Album.new(3, "Into the Beyond", [Song.new("Rhythm of the night", "Into the Beyond"), Song.new("I'm blue", "Into the Beyond")], "S3KR3TK0D3"),
112-
]
113-
end
114-
115-
it do
116-
represented = AlbumRepresenter.for_collection.new(albums).to_object(cover_png: cover_png)
117-
assert_equal represented.size, albums.size
118-
assert_respond_to albums[0], :free_concert_ticket_promo_code
119-
refute_respond_to represented[0], :free_concert_ticket_promo_code
120-
assert_equal represented[0].cover_png, cover_png
121-
assert_equal represented[0].class.object_id, represented[1].class.object_id
122-
end
123-
124-
let(:wrapper) { "cool_album" }
125-
let(:second_wrapper) { "magnificent_album" }
126-
it do
127-
represented_array = AlbumRepresenter.for_collection.new(albums).to_object(wrap: wrapper)
128-
represented_object = AlbumRepresenter.new(album).to_object(wrap: second_wrapper)
129-
130-
assert_respond_to represented_array, wrapper
131-
132-
assert_respond_to represented_array.send(wrapper)[0], wrapper
133-
first_song_title_represented = represented_array.send(wrapper)[0].send(wrapper).songs[0].title
134-
first_song_title_original = albums[0].songs[0].title
135-
assert_equal first_song_title_represented, first_song_title_original.upcase
136-
137-
assert_equal represented_array.send(wrapper)[0].class.object_id, represented_array.send(wrapper)[1].class.object_id # wrapper struct class is the same for collection
138-
refute_equal represented_array.send(wrapper)[0].class.object_id, represented_object.class.object_id # wrapper structs classes are different for different wrappers
139-
end
14060
end

0 commit comments

Comments
 (0)