solnic / virtus

[DISCONTINUED ] Attributes on Steroids for Plain Old Ruby Objects
MIT License
3.77k stars 229 forks source link

Attribute defaults #252

Closed fgarcia closed 10 years ago

fgarcia commented 10 years ago

Is there any easy way to write Virtus objects where all attributes are by default "String" AND "Private" (but still shown when converted to a hash)?

Regarding private values this was my first thought:

class Foo
  include Virtus.model
  attribute :id, String
  attribute :value, String, :accessor => private
end

However while I wanted this:

a = Foo.new(id:"5", value:"5343")
a.value # access error

I got a class where the new constructor takes 0 arguments

This is more of a support question, if StackOverflow (or somewhere else) is a better place, just point me to the right direction. However I thought it was valuable asking here just to show one way I am trying to use the gem.

solnic commented 10 years ago

I'm not seeing this. Can you write an executable script showing the problem? And expected behavior?

fgarcia commented 10 years ago

Grrr... after making this gist:

https://gist.github.com/fgarcia/9277156

I realized I should solve my problem with the decorator pattern!

I still do not know how to define private attributes, but now I am starting to believe that private attributes defeat the purpose of Virtus models.

You should close this issue, I think I can solve myself how to make a Value Object out of a normal Virtus definition. It is just some rare thing where I never use normal Virtus objects. It is either as a Value Object (stateless) or as a decorated object (with state, but hiding all attributes).

solnic commented 10 years ago

why are you writing :accessor => private instead of :accessor => :private? :)

fgarcia commented 10 years ago

maaan, I dunno know if I need sleep or a big slap on my face!

Am Freitag, 28. Februar 2014 schrieb Piotr Solnica :

why are you writing :accessor => private instead of :accessor => :private? :)

Reply to this email directly or view it on GitHubhttps://github.com/solnic/virtus/issues/252#issuecomment-36401717 .

solnic commented 10 years ago

Shit happens, no worries :)

I suspect it works, right?

On Fri, Feb 28, 2014 at 11:39 PM, Francisco Garcia notifications@github.com wrote:

maaan, I dunno know if I need sleep or a big slap on my face! Am Freitag, 28. Februar 2014 schrieb Piotr Solnica :

why are you writing :accessor => private instead of :accessor => :private? :)

Reply to this email directly or view it on GitHubhttps://github.com/solnic/virtus/issues/252#issuecomment-36401717 .


Reply to this email directly or view it on GitHub: https://github.com/solnic/virtus/issues/252#issuecomment-36402008

fgarcia commented 10 years ago

After some sleep made it work, but here is what I expected vs what I got:

require 'virtus'

class Foo
  include Virtus.model
  attribute :name, String
  attribute :value, String, :accessor => :private
end

2.1.0 (main):0 > a = Foo.new(name:'fran', value:'a thing')
=> #<Foo:0x007fd2da8f9be8 @name="fran", @value=nil>

2.1.0 (main):0 > a.send(:value)
=> nil

2.1.0 (main):0 > a.to_hash
=> {
  :name => "fran"
}

I expected being able to define the attribute value during the object initialization.

A more controversial thing is showing private attributes when casting to_hash . Maybe everyone will have a different opinion on what should be the default behavior, but I wonder if this can be changed.

solnic commented 10 years ago

You want public writer and private reader, I suppose. If you set accessor to private then both writer and reader methods will be private and virtus disallows mass-assignment of attributes with private writers.

This is how it works in 1.0 at least. I will revisit this in 2.0. I'm gonna close this issue for now.

fgarcia commented 10 years ago

woah! impresive response time. Hope you also sleep! If we meet at any RubyConf I will owe you so many gratitude beers

I did a wrong use of :accessor, I should have written:

attribute :value, String, :writter => :private

More exactly I wanted private writter and public reader. Even so, my expectation was that private writter meant I could write during initialization, but not write afterwards. Just verified that my initialization for that :value gets ignored.

I am set to explore ROM now. I believe I was adding too many responsibilities to Virtus that fit better ROM.

Thank you so much also for all the work on that front!

solnic commented 10 years ago

In that case you want to use Virtus.value_object which doesn't allow changing an object after it was initialized.

Re beers and confs, I'm going to wroc_love.rb and RedDotRubyConf this year ;) Maybe some more ;)

bguest commented 9 years ago

It would be nice to be able to mark some attributes as imutable, ie you can define them durring initialization, but not after ie:

class User
  attribute :user_id, Integer, :accessor => :immutable
  attribute :name, String
end

uu = User.new(:user_id => 33)
uu.user_id  #=> 33
uu.user_id = 10      #error
uu.name = 'Bob'
uu.name  #=> 'Bob'