Skip to content
This repository was archived by the owner on Oct 19, 2018. It is now read-only.

Rewriting in JS

Mitch VanDuyn edited this page Aug 3, 2017 · 6 revisions

What would happen if the entire hyperloop internal code base was rewritten in JS and used JS classes and objects, instead of in opal-ruby.

Here is an experiment:

Take the following code (from hyper-model)

module React
  class State

    ALWAYS_UPDATE_STATE_AFTER_RENDER = Hyperloop.on_client? # if on server then we don't wait to update the state
    @rendering_level = 0

    class << self
      attr_reader :current_observer
      
      def observers_by_name 
          @observers_by_name ||= Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = [] } }
      end

      def has_observers?(object, name)
        !observers_by_name[object][name].empty?
      end

      def bulk_update
        saved_bulk_update_flag = @bulk_update_flag
        @bulk_update_flag = true
        yield
      ensure
        @bulk_update_flag = saved_bulk_update_flag
      end

      def set_state2(object, name, value, updates, exclusions = nil)
        # set object's name state to value, tell all observers it has changed.
        # Observers must implement update_react_js_state
        object_needs_notification = object.respond_to? :update_react_js_state
        observers_by_name[object][name].dup.each do |observer|
          next if exclusions && exclusions.include?(observer)
          updates[observer] += [object, name, value]
          object_needs_notification = false if object == observer
        end
        updates[object] += [nil, name, value] if object_needs_notification
      end

      def initialize_states(object, initial_values) # initialize objects' name/value pairs
        states[object].merge!(initial_values || {})
      end

      def get_state(object, name, current_observer = @current_observer)
        # get current value of name for object, remember that the current object depends on this state,
        # current observer can be overriden with last param
        if current_observer && !new_observers[current_observer][object].include?(name)
          new_observers[current_observer][object] << name
        end
        if @delayed_updates && @delayed_updates[object][name]
          @delayed_updates[object][name][1] << current_observer
        end
        states[object][name]
      end
      # lots of other methods ... follow
    end
  end
end

Here is the same functionality written in JS:

React.State = function () {
  var ALWAYS_UPDATE_STATE_AFTER_RENDER = Opal.Hyperloop['$on_client?']();
  var rendering_level = 0;
  var _current_observer;
  var by_name = {};
  var bulk_update_flag = false;
  var set_observer = function (observer, k1, k2, value) {
    if (!observer[k1]) { observer[k1] = {} }
    observer[k1][k2] = value
  };
  var get_observer = function (observer, k1, k2) {
    if (!observer[k1]) { return null }
    observer[k1][k2]
  };
  var set_state2 = function (object, name, value, updates, exclusions) {
    var object_needs_notification = object['respond_to?']('update_react_js_state')
    for (observer in get_observers(by_name, object, name).slice(0)) {
      if (!exclusions || !exclusions.includes(object)) {
         updates[observer].push([object, name, value])
         if (object == observer) { object_needs_notification = false }
      }
    }
    if (!object_needs_notification) { updates[object].push += [null, name, value] }
  }

  return {
    current_observer: function () { return _current_observer; }
    has_observers: function (object, name) {
      var r = get_observers(by_name, object, name)
      return r && r.length > 0)
    }
    bulk_update: function (fn) {
      var saved_bulk_update_flag = bulk_update_flag
      bulk_update_flag = true
      try { 
        fn();
      }
      finally {
        bulk_update_flag = saved_bulk_update_flag
      }
    }
    
	var myPrivateVar = "I can be accessed only from within YAHOO.myProject.myModule.";
	
	//"private" method:
	var myPrivateMethod = function () {
		YAHOO.log("I can be accessed only from within YAHOO.myProject.myModule");
	}


	return  {
		myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty.",
		myPublicMethod: function () {
			YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");

			//Within myProject, I can access "private" vars and methods:
			YAHOO.log(myPrivateVar);
			YAHOO.log(myPrivateMethod());

			//The native scope of myPublicMethod is myProject; we can
			//access public members using "this":
			YAHOO.log(this.myPublicProperty);
		}
	};

}();
Clone this wiki locally