Skip to content

Commit 67869b5

Browse files
authored
Create current-status.md
1 parent ba19081 commit 67869b5

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed

current-status.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
### Current Status: Working towards 0.1 release. See Roadmap for details.
2+
3+
`hyperstack-config`, `hyper-store`, and `hyper-component` are now following the public interface conventions.
4+
5+
I.e. to create a component you now do this:
6+
7+
```ruby
8+
class MyComponent
9+
include Hyperstack::Component
10+
...
11+
end
12+
```
13+
14+
The philosophy is that you will probably have a base class defined like this:
15+
16+
```ruby
17+
class HyperComponent
18+
include Hyperstack::Component
19+
end
20+
```
21+
22+
Which you can then inherit from.
23+
24+
The bigger change is that the state mechanism has now been greatly simplified, but you can choose when to move
25+
into the future by your choice of which module to include:
26+
27+
```ruby
28+
class HyperComponent
29+
include Hyperstack::Component
30+
# to use the current state/store syntax in your components:
31+
include Hyperstack::Legacy::Store
32+
end
33+
34+
class HyperStore
35+
# to use the legacy state store syntax in your stores:
36+
include Hyperstack::Legacy::Store
37+
end
38+
```
39+
40+
To use the new hotness change the includes:
41+
42+
```ruby
43+
class HyperComponent
44+
include Hyperstack::Component
45+
# to use the current state/store syntax in your components:
46+
include Hyperstack::State::Observable
47+
end
48+
49+
class HyperStore
50+
# to use the legacy state store syntax in your stores:
51+
include Hyperstack::State::Observable
52+
end
53+
```
54+
55+
In summary you will need to update your hyperloop/hyperstack components and store folders to have `hyper_component.rb`
56+
and `hyper_store.rb` files. And then update your components and stores to reference your application defined `HyperComponent`
57+
and `HyperStore` classes.
58+
59+
### The new world of state:
60+
61+
Its great, its exciting, and its sooo much easier:
62+
63+
Each ruby object has *state*, defined by its instance variables. Hyperstack does not define *any new state concepts*. From
64+
now on you just use instance variables in your components and other objects as you normally would.
65+
66+
The one caveat is that you have to *tell* the system when you are *mutating* state, and when some external entity is
67+
*observing* your state.
68+
69+
The `Hyperstack::State::Observable` module provides a handful of methods to make this very easy.
70+
71+
Here is an example (compare to the state example on the [Hyperstack.org home page](https://hyperstack.org/))
72+
73+
```ruby
74+
class UsingState < Hyperloop::Component
75+
76+
# Our component has two instance variables to keep track of what is going on
77+
# @show - if true we will show an input box, otherwise the box is hidden
78+
# @input_value - tracks what the user is typing into the input box.
79+
# We use the mutate method to signal all observers when the state changes.
80+
81+
render(DIV) do
82+
# the button method returns an HTML element
83+
# .on(:click) is an event handeler
84+
button.on(:click) { mutate @show = !@show }
85+
DIV do
86+
input
87+
output
88+
easter_egg
89+
end if @show
90+
end
91+
92+
def button
93+
BUTTON(class: 'ui primary button') do
94+
@show ? 'Hide' : 'Show'
95+
end
96+
end
97+
98+
def input
99+
DIV(class: 'ui input fluid block') do
100+
INPUT(type: :text).on(:change) do |evt|
101+
# we are updating the value per keypress
102+
mutate @input_value = evt.target.value
103+
end
104+
end
105+
end
106+
107+
def output
108+
# this will re-render whenever input_value changes
109+
P { "#{@input_value}" }
110+
end
111+
112+
def easter_egg
113+
H2 {'you found it!'} if @input_value == 'egg'
114+
end
115+
end
116+
```
117+
118+
So to make our instance variables work with components we just need to call `mutate` when the state changes.
119+
120+
Here is a very simple store that is just a global click counter
121+
122+
```ruby
123+
class Click
124+
include Hyperstack::State::Observable
125+
class << self
126+
def count
127+
observe @count ||= 0
128+
end
129+
def inc
130+
mutate @count = count + 1
131+
end
132+
def count=(x)
133+
mutate @count = x
134+
end
135+
def reset
136+
mutate @count = 0
137+
end
138+
end
139+
end
140+
```
141+
142+
Now any component can access and change the counter by calling `Click.count`, `Click.inc` and `Click.reset` as needed.
143+
144+
The `observe` and `mutate` methods take no params (handy for adding to the end of a method), a single param as shown above,
145+
or a block in which case the entire block will be executed before signaling the rest of the system.
146+
147+
That is all there is to it, but to make things easier `Observable` contains some other helper methods which we can use:
148+
149+
```ruby
150+
class Click
151+
include Hyperstack::State::Observable
152+
class << self
153+
observer(:count) { @count ||= 0 }
154+
state_writer :count
155+
mutator(:inc) { count = count + 1 }
156+
mutator(:reset) { count = 0 }
157+
end
158+
end
159+
```
160+
161+
The `observer` and `mutator` methods create a method wrapped in `observe` or `mutate` block.
162+
163+
In addition there are `state_accessor`, `state_reader` and `state_writer` methods that work just like `attr_accessor` methods
164+
except access is wrapped in the appropriate `mutate` or `observe` method.
165+
166+
The methods can be used either at the class or instance level as needed.
167+
168+
Because stateful components use the same `Observable` module all the above methods are available to help structure your
169+
components nicely.
170+
171+
Notice in the component example we never use `observe` that is because by definition components always `observe` their own
172+
state automatically so you don't need to.
173+

0 commit comments

Comments
 (0)