# Hyperstack # ----------------------------------- Commit so we have good history of these changes git :init git add: "." git commit: "-m 'Initial commit: Rails base'" # ----------------------------------- Add the gems gem 'webpacker' gem 'rails-hyperstack', '~> 1.0.alpha1.0' gem_group :development do gem 'foreman' gem 'rubocop' end # ----------------------------------- Ensure Sqlite has a valid version # gsub_file 'Gemfile', /gem\s+'sqlite3'(?!,\s+'.*')\n/, "gem 'sqlite3', '~> 1.3.6'\n" # gsub_file 'Gemfile', /gem\s+'sqlite3'(?!,\s+'.*')\n/, "gem 'pg'" # ----------------------------------- Create the folders run 'mkdir app/hyperstack' run 'mkdir app/hyperstack/components' run 'mkdir app/hyperstack/stores' run 'mkdir app/hyperstack/models' run 'mkdir app/hyperstack/operations' run 'mkdir app/policies' # ----------------------------------- Add .keep files run 'touch app/hyperstack/stores/.keep' run 'touch app/hyperstack/models/.keep' run 'touch app/hyperstack/operations/.keep' # ----------------------------------- Create the HyperCompnent base class file 'app/hyperstack/components/hyper_component.rb', <<-CODE class HyperComponent include Hyperstack::Component include Hyperstack::State::Observable param_accessor_style :accessors end CODE # ----------------------------------- Create the public ApplicationRecord base class file 'app/hyperstack/models/application_record.rb', <<-CODE class ApplicationRecord < ActiveRecord::Base self.abstract_class = true regulate_scope all: true end CODE # ----------------------------------- reference the public application_record.rb file file 'app/models/application_record.rb', <<-CODE, force: true # app/models/application_record.rb # the presence of this file prevents rails migrations from recreating application_record.rb # see https://github.com/rails/rails/issues/29407 # BH - I am not sure this is right # require 'models/application_record.rb' CODE # ----------------------------------- Create the Hyperstack config file 'config/initializers/hyperstack.rb', <<-CODE # config/initializers/hyperstack.rb # If you are not using ActionCable, see http://hyperstack.orgs/docs/models/configuring-transport/ Hyperstack.configuration do |config| config.transport = :action_cable config.prerendering = :off # or :on config.cancel_import 'react/react-source-browser' # bring your own React and ReactRouter via Yarn/Webpacker config.import 'hyperstack/component/jquery', client_only: true # remove this line if you don't need jquery config.import 'hyperstack/hotloader', client_only: true if Rails.env.development? end if Rails.env.development? # useful for debugging module Hyperstack def self.on_error(operation, err, params, formatted_error_message) ::Rails.logger.debug( "\#{formatted_error_message}\\n\\n" + Pastel.new.red( 'To further investigate you may want to add a debugging '\\ 'breakpoint to the on_error method in config/initializers/hyperstack.rb' ) ) end end end CODE # ----------------------------------- Create thyperstack.js file 'app/javascript/packs/hyperstack.js', <<-CODE // Import all the modules import React from 'react'; import ReactDOM from 'react-dom'; // for opal/hyperloop modules to find React and others they must explicitly be saved // to the global space, otherwise webpack will encapsulate them locally here global.React = React; global.ReactDOM = ReactDOM; CODE # ----------------------------------- View template inject_into_file 'app/views/layouts/application.html.erb', before: %r{<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>} do <<-CODE <%= javascript_pack_tag 'hyperstack' %> CODE end # ----------------------------------- Add a default policy file 'app/policies/application_policy.rb', <<-CODE # Policies regulate access to your public models # The following policy will open up full access (but only in development) # The policy system is very flexible and powerful. See the documentation # for complete details. if Rails.env.production? ::Rails.logger.warn("WARNING: You need to define a Hyperstack policy for production") else class Hyperstack::ApplicationPolicy # Allow any session to connect always_allow_connection # Send all attributes from all public models regulate_all_broadcasts { |policy| policy.send_all } # Allow all changes to public models allow_change(to: :all, on: %i[create update destroy]) { true } # Allow remote access to all scopes - i.e. you can count or get a list of ids # for any scope or relationship ApplicationRecord.regulate_scope :all end end CODE # ----------------------------------- Add NPM modules run 'yarn add react@16' run 'yarn add react-dom@16' run 'yarn add react-router@^5.0.0' run 'yarn add react-router-dom@^5.0.0' # run 'yarn add history' # this will be brought in by react-router run 'yarn add react_ujs@^2.5.0' run 'yarn add jquery@^3.4.1' # ----------------------------------- application.js inject_into_file 'app/assets/javascripts/application.js', before: %r{//= require_tree .} do <<-CODE //= require jquery //= require jquery_ujs //= require hyperstack-loader CODE end # ----------------------------------- Uglifier for ES6 gsub_file 'config/environments/production.rb', /(?:\:uglifier)\n/, "Uglifier.new(harmony: true)\n" # ----------------------------------- Procfile file 'Procfile', <<-CODE web: bundle exec rails s -b 0.0.0.0 hot: hyperstack-hotloader -p 25222 -d app/hyperstack/ CODE # ----------------------------------- .rubocop.yml file '.rubocop.yml', <<-'CODE' # Prevent rubocop from prefixing unused arguments # with an underscore. We might be using the argument # in a syntax (e.g. `javascript`) that Rubocop # doesn't understand. Lint/UnusedBlockArgument: Enabled: false Lint/UnusedMethodArgument: Enabled: false # Increase allowed method/class/block/etc. # length and complexity. These values are # completely arbitrary. Feel free to adjust # as you see fit. Metrics/AbcSize: Max: 20 Metrics/BlockLength: Max: 80 Metrics/ClassLength: Max: 240 Metrics/MethodLength: Max: 12 Metrics/LineLength: Max: 180 # Allow to use { } for multi-line blocks Style/BlockDelimiters: Enabled: false # Allow compact class/module style; Foo::Bar Style/ClassAndModuleChildren: Enabled: false # Allow: assert_match /foo bar regex/, err.message Lint/AmbiguousRegexpLiteral: Enabled: false # Allow comment after keyword, like: # def foo # ..long method.. # end # /foo Style/CommentedKeyword: Enabled: false # Don't nag about missing comments Style/Documentation: Enabled: false # Allow top-level 'include' in scripts Style/MixinUsage: Exclude: - 'bin/*' # Allow chained blocks (javascript-style) Style/MultilineBlockChain: Enabled: false # Allow 'foo == 0' instead of 'foo.zero?' Style/NumericPredicate: Enabled: false # Sometimes humans feel better with an explicit begin. Style/RedundantBegin: Enabled: false # Sometimes humans feel better with an explicit return. Style/RedundantReturn: Enabled: false # Sometimes humans want to write ; things ; in a ; condensed ; fashion Style/Semicolon: Enabled: false # Sometimes humans disagree with rubocop. Style/GuardClause: Enabled: false # Allow double-quotes ("foo") even when there is no interpolation. # There is no performance difference and therefore no reason # to be a pain in the ass about it. Style/StringLiterals: Enabled: false # Allow blocks that call `send_all`. # *** DO NOT REMOVE THIS RULE! *** # Hyperstack frequently requires this syntax. # Your code will break if you let rubocop change it. Style/SymbolProc: Enabled: false # Allow "#{foo}". # *** DO NOT REMOVE THIS RULE! *** # Hyperstack frequently requires this syntax. # Your code will break if you let rubocop change it. Style/UnneededInterpolation: Enabled: false # If you don't understand what this does then # best leave it disabled. Re-enabling it will # _likely_ not break anything. But you may get # cryptic warnings that are exceedingly unlikely # to help improve your code. Lint/Void: Enabled: false # Don't nag about missing magic comment '# frozen_string_literal: true'. # Neither Rails nor Hyperstack seem to endorse the practice of having it. Style/FrozenStringLiteralComment: Enabled: false CODE # ----------------------------------- App # must be inserted BEFORE the engine mount so it ends up after in the route file! route "get '/(*other)', to: 'hyperstack#app'" file 'app/hyperstack/components/app.rb', <<-CODE # app/hyperstack/component/app.rb # This is your top level component, the rails router will # direct all requests to mount this component. You may # then use the Route pseudo component to mount specific # subcomponents depending on the URL. class App < HyperComponent include Hyperstack::Router # define routes using the Route psuedo component. Examples: # Route('/foo', mounts: Foo) : match the path beginning with /foo and mount component Foo here # Route('/foo') { Foo(...) } : display the contents of the block # Route('/', exact: true, mounts: Home) : match the exact path / and mount the Home component # Route('/user/:id/name', mounts: UserName) : path segments beginning with a colon will be captured in the match param # see the hyper-router gem documentation for more details render(DIV) do H1 { "Hello world from Hyperstack!" } BUTTON { "Click me" }.on(:click) do alert("All working!") end end end CODE # ----------------------------------- Engine mount point # must be inserted AFTER route get ... so it ends up before in the route file! route "mount Hyperstack::Engine => '/hyperstack'" # ----------------------------------- Commit Hyperstack setup and create db after_bundle do run 'bundle exec rails webpacker:install' # We let rubocop fix all linter problems # that are auto-fixable. This normally leads # to a lint-clean installation. run 'rubocop -a' git add: "." git commit: "-m 'Hyperstack config complete'" run 'rake db:create' end