lib/rydux/store.rb in rydux-0.9.1 vs lib/rydux/store.rb in rydux-0.9.2

- old
+ new

@@ -1,24 +1,12 @@ module Rydux class Store attr_reader :listeners - def initialize(combined_reducers) - @state = {} - @listeners = [] - @reducers = combined_reducers - - @reducers.each do |k, reducer| - if !reducer.ancestors.include? ::Rydux::Reducer - raise "Store expected a Reducer or array of reducers, but instead got: #{reducers}" - end - - new_state = {} - new_state[k] = reducer.map_state(type: nil) - - set_state(new_state) - end + def initialize(reducers) + @state, @listeners = {}, [] + @reducers = strap_reducers(reducers) end def subscribe(listener) @listeners << listener end @@ -26,41 +14,65 @@ # Unsubscribes a listener from the store def abandon(listener) @listeners.delete(listener) end - def dispatch(action) - @reducers.each do |k, reducer| - new_state = {} - new_state[k] = reducer.map_state(action, state[k]) - set_state(new_state, action[:type]) + # Dispatches an action to all reducers. Can be called any of the following ways: + # Takes in an action and an optional callback proc, which will be called after the + # dispatch is finished. + # The action can be passed in either as a hash or as two seperate arguments. + # E.g. dispatch({ type: 'SOME_ACTION', payload: { key: 'value' } }) + # is the same as dispatch('SOME_ACTION', { key: 'value' }) + # Here's an example with a proc: dispatch('SOME_ACTION', { key: 'value' }, ->{ puts "The dispatch is done" }) + def dispatch(*args) + if args.first.is_a? Hash + _dispatch(args.first, args[1]) + else + if args[1].is_a? Proc + _dispatch({ type: args.first }, args[1]) + else + _dispatch({ type: args.first, payload: args[1] }, args[2]) + end end end + # Return a clone of the current state so that the user cannot directly + # modify state, and introduce side effects def state State.new(@state) end private - def set_state(new_state, last_dispatch = nil) - new_state.each do |k, v| - @state[k] = v + def _dispatch(action, callback = ->{}) + @reducers.each {|k, reducer| set_state *[k, reducer.map_state(action, state[k])] } + callback.call if callback + end - if !self.methods.include? k - self.define_singleton_method(k.to_sym) do - return State.new(state[k]) - end - end + # Initialize state with the key-value pair associated with each reducer + def strap_reducers(reducers) + reducers.each {|k, reducer| set_state *[k, reducer.map_state(type: nil)]} + reducers + end - notify_listeners(last_dispatch) + # Argument 1 should always be the key within state that we're mutating + # Argument 2 should be the actual state object + def set_state(k, v) + @state[k] = v + + if !self.methods.include? k + self.define_singleton_method(k.to_sym) do + return State.new(@state[k]) + end end + + notify_listeners end - def notify_listeners(last_dispatch) + def notify_listeners @listeners.each do |listener| if listener.respond_to? :state_changed - listener.public_send(:state_changed, state, last_dispatch) + listener.public_send(:state_changed, state) end end end end