Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need a way to deal with objects changing state (i.e. arrays) #24

Closed
catmando opened this issue May 3, 2015 · 9 comments
Closed

Need a way to deal with objects changing state (i.e. arrays) #24

catmando opened this issue May 3, 2015 · 9 comments

Comments

@catmando
Copy link
Collaborator

catmando commented May 3, 2015

For example

define_state(:foo) { ['joe', 'fred'] }

def add_friend(friend) 
  foo << friend
end

This does not work as foo << friend updates the array object, but there is no way to know that the foo state has been updated.

I have implemented a couple of solutions, and am interested in which people would prefer:

  1. define foo! method that will return an object that wrap the current value of foo, and observe any changes to that object. So you can write
def add_friend(friend)
  foo! << friend
end
  1. define foo! method that simple does foo = foo to indicate a state change. This would return self so that the methods could be chained
def add_friend(friend)
  foo << friend; foo!
end

or

def add_friend(friend)
  foo << friend
ensure
  foo!.bar!
end

2b) In addition the Proc class can be updated so this works

lambda { |new_friend| foo << new_friend }.foo! 

Just looking for people's input, preferences, or other ideas!

@zetachang
Copy link
Owner

Thanks for pointing this out, I think this could be a common mistake given that the original setState is wrapped inside the setter.

Currently, you can write as below,

def add_friend(friend)
  self.foo = foo << friend; self
end

To get the benefit of brevity and also make it chainable.

@catmando
Copy link
Collaborator Author

catmando commented May 4, 2015

I understand that the current solution is to do something like you said above...

My intention is to add a solution that will read cleaner and be shorter.

I have implemented the all the solutions suggested above, and after playing with them in some code feel that just adding the foo! method is the easiest and cleanest.

I.e. foo! << friend is equal to foo << friend; self.foo = foo

If I do a pull request with this will you accept it?

@zetachang
Copy link
Owner

I think I get your point now, looks like a nice to have feature. Feel free to open up a pull request 👍

@catmando
Copy link
Collaborator Author

catmando commented May 6, 2015

i've made some more improvements to this... expect a pull request soon, but first I am integrating with some real code to see how everything feels.

Basically there is now a foo! method that can be either used to send a new value to foo as in foo!('new value') (equivilent to self.foo = 'new value')
or if no parameter is provided then foo! returns an object that will update after any method calls on foo. This is nice because foo! consistently means update foo, and foo! 'new value' is shorter and less error prone than self.foo = 'new value'. (I say less error prone because you don't have to remember to include self.

In addition I added two class methods require_param and optional_param that will declare a validated parameter. The difference is these methods will also create methods that can read the parameters directly.

I.e. require_param :foo, type: String will require a foo parameter and will create a foo method that returns that parameter.

Finally if the type of parameter is Proc then the created method will call the proc. So

require_param :foo, type: Proc

then

foo 1,2,3

will send 1,2,3 to whatever Proc foo got bound to.

Altogether these changes clean things up so that things read really nicely.

Oh yeah two other things:

You can say class MyComponent < React::Component::Base instead of including React::Component

And any class that responds to 'render' can be used in the rendering dsl. So you can say

div do
  my_component param_1: 'Joe', param_2: 'Fred'
end

As long as an instance of MyComponent responds to render...

How does all that sound :-)

@zetachang
Copy link
Owner

Hey, thanks for taking time making this suggestion.

or if no parameter is provided then foo! returns an object that will update after any method calls on foo.

How is this going to be implemented? A wrapper object which will delegate all method invocations?

In addition I added two class methods require_param and optional_param that will declare a validated parameter. The difference is these methods will also create methods that can read the parameters directly.

We currently got a params class methods, it becomes complicated for me to choose which one to use if another require_params, optional_params is introduced. So maybe add a new parameter, that's say accessor: true. So you can write like this,

params do
    requires :foo, type: Proc, accessor: true
end

Finally if the type of parameter is Proc then the created method will call the proc.

This is actually quite neat, 👍 on this.

You can say class MyComponent < React::Component::Base instead of including React::Component

Would you mind elaborating more on why having a base class rather than current module approach? The initial design decision made is to allow every Ruby class got render defined could be valid component. React::Component only provide helper methods. And there is a lot of refactoring work for React::Component on #17 , so I will suggest postponing this until it's done.

And any class that responds to 'render' can be used in the rendering dsl.

👍 on this.

Last but not least, would you mind open separate pull requests for these features? Thus we can review and merge them faster. 😃

@catmando
Copy link
Collaborator Author

catmando commented May 8, 2015

Thanks for the feedback... will discuss more on the pull request.

As I am using this in a real app, I am making adjustments to the API as I go

@catmando
Copy link
Collaborator Author

Okay.. I setup a WIP pull request... your comments on these items would be great.

@ajjahn
Copy link
Collaborator

ajjahn commented Oct 30, 2015

@catmando This is implemented as part of the state observer (! bang method) API. Right?

@sollycatprint
Copy link

This issue was moved to ruby-hyperloop/hyper-react#24

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants