server_component 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dba7844e0d4e1ca570d77659d7ef3eea346900fc8ab9e84afef4dba723bf8113
4
+ data.tar.gz: 8d331e9937dfc21a5f281724831a18ab9c56dc6168b4df3dc0ca398bea09d9dd
5
+ SHA512:
6
+ metadata.gz: a70a74596bbf8482aa244ed247bf04a8a412318c2aed0e8533c19715c9551a55099245bf8c7b93d02b5ebfd21b505c07734a655bb951dab25a9dcfc73df29796
7
+ data.tar.gz: 963688b759513463ef25f378c074830ec2e83710b1465a16ee1a5b31fc495eeabb3a798c3560dd405d58409d05a0747fab5e451ab3c38b0c3b5ea80b490377e7
@@ -0,0 +1,42 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+ jobs:
7
+ build:
8
+ docker:
9
+ - image: circleci/ruby:2.5.1-node-browsers
10
+ working_directory: ~/repo
11
+ steps:
12
+ - checkout
13
+ - run:
14
+ name: install dependencies
15
+ working_directory: ~/repo
16
+ command: |
17
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
18
+ - run:
19
+ name: install binstubs
20
+ working_directory: ~/repo
21
+ command: |
22
+ bundle exec rake app:update:bin webpacker:binstubs
23
+ - run:
24
+ name: install dependencies
25
+ working_directory: ~/repo/spec/dummy
26
+ command: |
27
+ yarn install
28
+ - run:
29
+ name: run tests
30
+ working_directory: ~/repo
31
+ command: |
32
+ bundle exec rspec
33
+ - run:
34
+ name: run rubocop
35
+ working_directory: ~/repo
36
+ command: |
37
+ bundle exec rubocop
38
+ - run:
39
+ name: report coverage
40
+ working_directory: ~/repo
41
+ command: |
42
+ bash <(curl -s https://codecov.io/bash) -f coverage/.resultset.json
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/dummy/log/*
8
+ /spec/reports/
9
+ /tmp/
10
+ /spec/dummy/bin
11
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,46 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'lib/generators/templates/**/*'
4
+ - 'tmp/**/*'
5
+ - 'bin/*'
6
+ - 'spec/dummy/bin/**/*'
7
+ - 'spec/dummy/node_modules/**/*'
8
+ - 'vendor/**/*'
9
+ TargetRubyVersion: 2.5
10
+
11
+ Metrics/LineLength:
12
+ Max: 130
13
+
14
+ Metrics/MethodLength:
15
+ Max: 30
16
+
17
+ Metrics/AbcSize:
18
+ Max: 25
19
+
20
+ Metrics/ClassLength:
21
+ Max: 200
22
+
23
+ Style/ClassVars:
24
+ Enabled: false
25
+
26
+ Style/MissingRespondToMissing:
27
+ Enabled: false
28
+
29
+ Style/GuardClause:
30
+ Enabled: false
31
+
32
+ Naming/MemoizedInstanceVariableName:
33
+ EnforcedStyleForLeadingUnderscores: optional
34
+
35
+ Style/Documentation:
36
+ Enabled: false
37
+
38
+ Style/AccessModifierDeclarations:
39
+ Enabled: false
40
+
41
+ Style/NumericPredicate:
42
+ Enabled: false
43
+
44
+ Metrics/BlockLength:
45
+ Exclude:
46
+ - 'spec/**/*'
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.13.6
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in server_component.gemspec
6
+ gemspec
7
+
8
+ gem 'execjs'
9
+ gem 'stitch-rb'
10
+
11
+ group :development, :test do
12
+ gem 'capybara', '~> 2.18.0'
13
+ gem 'pry-byebug'
14
+ gem 'rspec-rails', '~> 3.8'
15
+ gem 'rubocop'
16
+ gem 'selenium-webdriver'
17
+ gem 'simplecov'
18
+ gem 'webpacker', '4.0.0.rc.2'
19
+ end
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ [![CircleCI](https://circleci.com/gh/effective-spa/server_component_rails.svg?style=svg)](https://circleci.com/gh/effective-spa/server_component_rails) [![codecov](https://codecov.io/gh/effective-spa/server_component_rails/branch/master/graph/badge.svg)](https://codecov.io/gh/effective-spa/server_component_rails) [![Maintainability](https://api.codeclimate.com/v1/badges/3a8af74f091ff7c3dbf4/maintainability)](https://codeclimate.com/github/effective-spa/server_component_rails/maintainability)
2
+
3
+ # ServerComponent
4
+
5
+ ServerComponent makes it possible to implement React component as Rails controller.
6
+ This gem is designed to be used with [server_component](https://github.com/effective-spa/server_component) NPM package.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile and run `bundle install`:
11
+
12
+ ```ruby
13
+ gem 'server_component'
14
+ ```
15
+
16
+ Run this command to initialize configuration file and base classes.
17
+
18
+ ```sh
19
+ $ rails generate server_component:install
20
+ ```
21
+
22
+ ## Getting Started
23
+
24
+ Add a new component controller:
25
+
26
+ ```rb
27
+ class CounterComponentController < ServerComponent::ComponentController
28
+ def self.initial_state
29
+ {
30
+ count: 0
31
+ }
32
+ end
33
+
34
+ def increment
35
+ set_state do |s|
36
+ s.count { |prev| prev + 1 }
37
+ end
38
+ end
39
+
40
+ def decrement
41
+ set_state do |s|
42
+ s.count { |prev| prev - 1 }
43
+ end
44
+ end
45
+ end
46
+ ```
47
+
48
+ Specify in a component router:
49
+
50
+ ```rb
51
+ class ApiComponentRouter < ServerComponent::ComponentRouter
52
+ component :counter
53
+ end
54
+ ```
55
+
56
+ In the client code (with Babel >= 7):
57
+
58
+ ```js
59
+ import React, { Component } from 'react';
60
+ import ReactDOM from 'react-dom';
61
+ import ServerComponent, { server_component, consumer } from 'server_component';
62
+
63
+ @server_component('counter')
64
+ class CounterContainer extends Component { }
65
+
66
+ @consumer('counter')
67
+ class CounterBody extends Component {
68
+ render() {
69
+ const { increment, decrement, state: { count } } = this.props.counter;
70
+ return (
71
+ <div>
72
+ <h1>Counter</h1>
73
+ <button onClick={increment}>increment</button>
74
+ <button onClick={decrement}>decrement</button>
75
+ <hr />
76
+ <div>Count: {counter}</div>
77
+ </div>
78
+ );
79
+ }
80
+ }
81
+
82
+ class Main extends Component {
83
+ render() {
84
+ return (
85
+ <ServerComponent.Use at="/react" name="api">
86
+ <CounterContainer>
87
+ <CounterBody />
88
+ </CounterContainer>
89
+ </ServerComponent.Use>
90
+ );
91
+ }
92
+ }
93
+
94
+ ReactDOM.render(<Main />, document.getElementById('root'));
95
+ ```
96
+
97
+ ## API Documentation
98
+
99
+ (TODO)
100
+
101
+ ## Contributing
102
+
103
+ Bug reports and pull requests are welcome on GitHub at https://github.com/effective-spa/server_component.
104
+
105
+
106
+ ## License
107
+
108
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
9
+
10
+ # This let CI know tasks 'app:update:bin' and 'webpacker:binstubs'
11
+ require_relative 'spec/dummy/config/application'
12
+ Rails.application.load_tasks
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ class FetcherConfigurator
5
+ include ServerComponentHelper
6
+
7
+ def initialize(component_class, actions)
8
+ @component_class = component_class
9
+ @actions = actions
10
+ end
11
+
12
+ def before
13
+ jsrb = Jsrb::Base.new
14
+ set_state(jsrb) do |s|
15
+ yield(s, jsrb.expr.context.data)
16
+ end
17
+ set_value(:start_function, jsrb.generate_code)
18
+ end
19
+
20
+ def accept_file!
21
+ set_value :upload, true
22
+ end
23
+
24
+ def set_value(key, value)
25
+ @actions.each do |action|
26
+ @component_class.action_descriptors[action][key] = value
27
+ end
28
+ end
29
+ end
30
+
31
+ class BaseComponentController < ServerComponent.parent_controller.constantize
32
+ class_attribute :initial_state, :action_on_mount
33
+
34
+ helper ServerComponentHelper
35
+ include ServerComponentHelper
36
+
37
+ private
38
+
39
+ def set_state(&block) # rubocop:disable Naming/AccessorMethodName
40
+ jsrb = Jsrb::Base.new
41
+ super(jsrb, &block)
42
+ render jsrb: jsrb.generate_code
43
+ end
44
+
45
+ class << self
46
+ def to_json
47
+ {
48
+ action_on_mount: action_on_mount,
49
+ initial_state: initial_state,
50
+ actions: action_descriptors
51
+ }
52
+ end
53
+
54
+ def action_descriptors
55
+ if instance_variable_defined?('@action_descriptors')
56
+ instance_variable_get '@action_descriptors'
57
+ else
58
+ h = {}
59
+ instance_variable_set '@action_descriptors', h
60
+ h
61
+ end
62
+ end
63
+
64
+ def action(*action_names, &block)
65
+ options = action_names.extract_options!
66
+ raise ArgumentError, 'specify at least one action!' if action_names.empty?
67
+
68
+ action_names.each do |action_name|
69
+ action_descriptors[action_name.to_sym] = {}
70
+ end
71
+ fetcher(*action_names, &block) if block
72
+ if options[:on_mount]
73
+ raise ArgumentError, 'on_mount option can accept only one action' if action_names.size > 1
74
+
75
+ on_mount action_names.first
76
+ end
77
+ end
78
+
79
+ def on_mount(action)
80
+ self.action_on_mount = action
81
+ end
82
+
83
+ def fetcher(*actions)
84
+ configurator = FetcherConfigurator.new(self, actions.map(&:to_sym))
85
+ yield configurator
86
+ end
87
+
88
+ def before(*actions, &block)
89
+ fetcher(*actions) do |c|
90
+ c.before(&block)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ class ComponentRoutersController < ServerComponent.parent_controller.constantize
5
+ def show
6
+ component_router = find_component_router
7
+ render json: component_router.to_json
8
+ end
9
+
10
+ private
11
+
12
+ def find_component_router
13
+ component_router_class_name = "#{name.camelize}ComponentRouter"
14
+ component_router_class =
15
+ begin
16
+ component_router_class_name.constantize
17
+ rescue NameError
18
+ raise ActionController::RoutingError, "No route matches routes/#{name}"
19
+ end
20
+ component_router_class.new
21
+ end
22
+
23
+ def name
24
+ params[:name]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ class ComponentsController < ServerComponent.parent_controller.constantize
5
+ def perform
6
+ component_class = find_component_class!
7
+ component_class.dispatch(component_action, request, response)
8
+ end
9
+
10
+ private
11
+
12
+ def find_component_class!
13
+ klass_name = "#{component_name.camelize}ComponentController"
14
+ klass =
15
+ begin
16
+ klass_name.constantize
17
+ rescue NameError
18
+ raise ActionController::RoutingError, "No route matches #{component_name}/#{component_action}"
19
+ end
20
+ unless klass <= ServerComponent::BaseComponentController
21
+ raise ActionController::RoutingError, "No route matches #{component_name}/#{component_action}"
22
+ end
23
+
24
+ klass
25
+ end
26
+
27
+ def component_name
28
+ params[:component_name]
29
+ end
30
+
31
+ def component_action
32
+ params[:component_action_name]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponentHelper
4
+ class SetStateDSL
5
+ def initialize(new_state, prev_state)
6
+ @new_state = new_state
7
+ @prev_state = prev_state
8
+ end
9
+
10
+ # rubocop:disable Style/MethodMissingSuper
11
+ def method_missing(name, *args)
12
+ if (matches = name.to_s.match(/^(.+)=$/))
13
+ @new_state.member!(matches[1]).assign!(args[0]).as_statement!
14
+ elsif block_given?
15
+ block_result = yield @prev_state.member!(name)
16
+ @new_state.member!(name).assign!(block_result).as_statement!
17
+ else
18
+ @new_state.member!(name)
19
+ end
20
+ end
21
+ # rubocop:enable Style/MethodMissingSuper
22
+ end
23
+
24
+ def set_state(jsrb) # rubocop:disable Naming/AccessorMethodName
25
+ new_state = jsrb.var! { {} }
26
+ prev_state = jsrb.expr.component.state
27
+ yield SetStateDSL.new(new_state, prev_state)
28
+ jsrb.expr.component.setState.call(new_state).as_statement!
29
+ end
30
+ end
data/bin/rails ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This is a manually created bin file.
4
+ # Some webpacker tasks depend on the current directory,
5
+ # which is fixed in https://github.com/rails/webpacker/pull/1475
6
+ # but in webpacker 3.x, it's not fixed yet;)
7
+ APP_PATH = File.expand_path('../spec/dummy/config/application', __dir__)
8
+ require_relative '../spec/dummy/config/boot'
9
+ require 'rails/commands'
data/bin/webpack ADDED
@@ -0,0 +1,4 @@
1
+ # The existence of this file is checked by webpacker
2
+ # before webpacker:binstubs task,
3
+ # though bin files are installed into spec/dummy/bin.
4
+ # It seems bins should be in ./bin ?
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ ServerComponent::Engine.routes.draw do
4
+ get '/routes/:name' => 'component_routers#show'
5
+ post '/components/*component_name/:component_action_name' => 'components#perform'
6
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ module Generators
5
+ class ComponentControllerGenerator < Rails::Generators::NamedBase
6
+ source_root File.expand_path('../templates', __dir__)
7
+
8
+ desc 'Creates a ServerComponent initializer.'
9
+
10
+ def create_controller_file
11
+ template 'component_controller.rb', File.join('app/controllers', class_path, "#{file_name}_component_controller.rb")
12
+ end
13
+
14
+ def component
15
+ rgx = /class [A-z::]+ComponentRouter < ServerComponent::ComponentRouter\n/
16
+ router_path = File.join('app/component_routers', "#{router_name}_component_router.rb")
17
+ routing_code = " component '#{name}'\n"
18
+ inject_into_file router_path, routing_code, after: rgx
19
+ end
20
+
21
+ private
22
+
23
+ def router_name
24
+ @options.fetch(:router, 'api')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __dir__)
7
+
8
+ desc 'Creates a ServerComponent initializer.'
9
+
10
+ def create_initializer_file
11
+ template 'server_component.rb', 'config/initializers/server_component.rb'
12
+ end
13
+
14
+ def setup_route
15
+ route "mount ServerComponent::Engine, at: 'react'"
16
+ end
17
+
18
+ def create_directory
19
+ empty_directory 'app/component_routers'
20
+ end
21
+
22
+ def add_one_router
23
+ template 'api_component_router.rb', 'app/component_routers/api_component_router.rb'
24
+ end
25
+
26
+ def show_readme
27
+ readme 'AFTER_INSTALL' if behavior == :invoke
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ ===============================================================================
2
+
3
+ What's next:
4
+
5
+ 1. Add "component_routers" directory into autoload_paths
6
+ in config/application.rb
7
+
8
+ config.autoload_paths << Rails.root.join('component_routers')
9
+
10
+
11
+ 2. Create component controller. If you want BookComponent for example, run:
12
+
13
+ $ rails generate server_component:component_controller book --router api
14
+
15
+
16
+ 3. Conjoin client application with `server_component`:
17
+
18
+ // Create a component class.
19
+
20
+ @ServerComponent.component('book')
21
+ class BookContainer extends React.Component {}
22
+
23
+ // Create a component-attached class.
24
+
25
+ @ServerComponent.attach('book')
26
+ class Book extends React.Component {
27
+ render() {
28
+ const { state: { list } } = this.props.book;
29
+ return (
30
+ <ul>
31
+ {list.map(book => <li>{book.title}</li>)}
32
+ </ul>
33
+ );
34
+ }
35
+ }
36
+
37
+ // And use in your root render function:
38
+
39
+ <ServerComponent.Use at="/react" name="api">
40
+ <BookContainer>
41
+ <Book />
42
+ </BookContainer>
43
+ </ServerComponent.Use>
44
+
45
+ ===============================================================================
@@ -0,0 +1,3 @@
1
+ class ApiComponentRouter < ServerComponent::ComponentRouter
2
+ # component :simple_counter
3
+ end
@@ -0,0 +1,5 @@
1
+ class <%= class_name %>ComponentController < ServerComponent::BaseComponentController
2
+ # def self.initial_state
3
+ # {}
4
+ # end
5
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Use this hook to configure ServerComponent
4
+ ServerComponent.setup do |config|
5
+ # context_script is executed before response scripts.
6
+ # It is useful if you want to add functions
7
+ # invoked from JSRB renderer.
8
+ # You can get identifiers from JSRB by calling
9
+ # `js.identifier_name` .
10
+ # The combination of 'add_custom_chain' option will
11
+ # make your JSRB code more readable.
12
+ config.context_script = <<~JAVASCRIPT
13
+ // Returns new object or array
14
+ // updating a property by immediate value or updator
15
+ // function in the specified path.
16
+ // without side effect in the original.
17
+ //
18
+ // example:
19
+ // immutable_update({ foo: 1 }, 'foo', 2) => { foo: 2 }
20
+ //
21
+ var immutable_update = (function () {
22
+ function _is_array(target) {
23
+ return Object.prototype.toString.call(target) === '[object Array]';
24
+ }
25
+
26
+ function _is_object(target) {
27
+ return typeof target === 'object' && target !== null;
28
+ }
29
+
30
+ function _clone_array_or_object(target) {
31
+ if (_is_array(target)) {
32
+ return target.slice(0);
33
+ } else if (_is_object(target)) {
34
+ return Object(target);
35
+ } else {
36
+ throw 'Argument Error: target is neither object nor array';
37
+ }
38
+ }
39
+
40
+ function _clone_update_internal(obj, field, value) {
41
+ if (value instanceof Function) {
42
+ obj[field] = value(obj[field]);
43
+ } else {
44
+ obj[field] = value;
45
+ }
46
+ }
47
+
48
+ return function (target, field, updator) {
49
+ var clone = _clone_array_or_object(target);
50
+ _clone_update_internal(clone, field, updator);
51
+ return clone;
52
+ }
53
+ })();
54
+ JAVASCRIPT
55
+
56
+ # Adds functionality to JSRB DSL.
57
+ # If you add 'func!' to 'some_func',
58
+ # then `obj.func!(arg)` is equivalent to `js.some_func.(obj, arg)`
59
+ # where `obj` is a chain instance in JSRB.
60
+ config.add_custom_chain(:update!, :immutable_update)
61
+
62
+ # Specify parent class of ServerComponent's controllers.
63
+ # config.parent_controller = 'ApplicationController'
64
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/dependencies'
4
+ require 'jsrb'
5
+
6
+ module ServerComponent
7
+ autoload :VERSION, 'server_component/version'
8
+ autoload :ComponentRouter, 'server_component/component_router'
9
+
10
+ class NamespaceNotFound < StandardError; end
11
+
12
+ mattr_accessor :parent_controller
13
+ @@parent_controller = 'ApplicationController'
14
+
15
+ def self.setup
16
+ yield self
17
+ end
18
+
19
+ mattr_accessor :context_script
20
+ @@context_script = ''
21
+
22
+ def self.add_custom_chain(name, function_name)
23
+ Jsrb::ExprChain.add_custom_chain name, function_name
24
+ end
25
+ end
26
+
27
+ require 'server_component/engine'
28
+ require 'server_component/jsrb_handler'
29
+ require 'server_component/railtie' if defined?(Rails)
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ class ComponentRouter
5
+ class_attribute :_namespace
6
+
7
+ def to_json
8
+ h = {}
9
+ h[:components] = components.each_with_object({}) do |component, json|
10
+ component_controller_class = find_component_controller_class(component)
11
+ json[component] = component_controller_class.to_json
12
+ end
13
+ h[:context_script] = context_script
14
+ h
15
+ end
16
+
17
+ def components
18
+ self.class.components
19
+ end
20
+
21
+ def namespace
22
+ self.class._namespace
23
+ end
24
+
25
+ def context_script
26
+ ServerComponent.context_script
27
+ end
28
+
29
+ protected
30
+
31
+ def find_component_controller_class(component)
32
+ name = (namespace ? "#{namespace}/#{component}" : component).to_s
33
+ "#{name.camelize}ComponentController".constantize
34
+ end
35
+
36
+ class << self
37
+ def namespace(mod)
38
+ self._namespace = mod
39
+ end
40
+
41
+ def components
42
+ if instance_variable_defined?('@components')
43
+ instance_variable_get '@components'
44
+ else
45
+ a = []
46
+ instance_variable_set '@components', a
47
+ a
48
+ end
49
+ end
50
+
51
+ def component(*component_names)
52
+ component_names.each do |name|
53
+ components << name.to_sym
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace ServerComponent
6
+ end
7
+ end
File without changes
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class JsrbHandler
4
+ cattr_accessor :default_format
5
+ self.default_format = Mime[:js]
6
+
7
+ def self.call(template)
8
+ %(jsrb = Jsrb::Base.new; #{template.source}; jsrb.generate_code)
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ class Railtie < ::Rails::Railtie
5
+ initializer :server_component do
6
+ ActiveSupport.on_load :action_view do
7
+ ActionView::Template.register_template_handler :jsrb, JsrbHandler
8
+ end
9
+
10
+ ActiveSupport.on_load :action_controller do
11
+ ActionController::Renderers.add :jsrb do |obj, _options|
12
+ send_data obj.to_s, type: Mime[:js]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServerComponent
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'server_component/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'server_component'
9
+ spec.version = ServerComponent::VERSION
10
+ spec.authors = ['Shun MIZUKAMI']
11
+ spec.email = ['norainu234@gmail.com']
12
+
13
+ spec.summary = 'ServerComponent support for Rails'
14
+ spec.description = 'ServerComponent makes it possible to implement React component as Rails controller'
15
+ spec.homepage = 'https://github.com/effective-spa/server_component_rails'
16
+ spec.license = 'MIT'
17
+
18
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
20
+ if spec.respond_to?(:metadata)
21
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
22
+ else
23
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
24
+ 'public gem pushes.'
25
+ end
26
+
27
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
28
+ f.match(%r{^(test|spec|features)/})
29
+ end
30
+ spec.bindir = 'exe'
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ['lib']
33
+
34
+ spec.add_runtime_dependency 'jsrb', '~> 0.1'
35
+ spec.add_runtime_dependency 'rails', '~> 5.0', '>= 5.0.0'
36
+
37
+ spec.add_development_dependency 'bundler', '~> 1.13'
38
+ spec.add_development_dependency 'rake', '~> 10.0'
39
+ spec.add_development_dependency 'rspec', '~> 3.0'
40
+ end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: server_component
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shun MIZUKAMI
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-01-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jsrb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 5.0.0
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '5.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 5.0.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.13'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.13'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '10.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '10.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.0'
89
+ description: ServerComponent makes it possible to implement React component as Rails
90
+ controller
91
+ email:
92
+ - norainu234@gmail.com
93
+ executables: []
94
+ extensions: []
95
+ extra_rdoc_files: []
96
+ files:
97
+ - ".circleci/config.yml"
98
+ - ".gitignore"
99
+ - ".rspec"
100
+ - ".rubocop.yml"
101
+ - ".ruby-version"
102
+ - ".travis.yml"
103
+ - Gemfile
104
+ - README.md
105
+ - Rakefile
106
+ - app/controllers/server_component/base_component_controller.rb
107
+ - app/controllers/server_component/component_routers_controller.rb
108
+ - app/controllers/server_component/components_controller.rb
109
+ - app/helpers/server_component_helper.rb
110
+ - bin/rails
111
+ - bin/webpack
112
+ - config/routes.rb
113
+ - lib/generators/server_component/component_controller_generator.rb
114
+ - lib/generators/server_component/install_generator.rb
115
+ - lib/generators/templates/AFTER_INSTALL
116
+ - lib/generators/templates/api_component_router.rb
117
+ - lib/generators/templates/component_controller.rb.tt
118
+ - lib/generators/templates/server_component.rb
119
+ - lib/server_component.rb
120
+ - lib/server_component/component_router.rb
121
+ - lib/server_component/engine.rb
122
+ - lib/server_component/js_function_builder.rb
123
+ - lib/server_component/jsrb_handler.rb
124
+ - lib/server_component/railtie.rb
125
+ - lib/server_component/version.rb
126
+ - server_component.gemspec
127
+ homepage: https://github.com/effective-spa/server_component_rails
128
+ licenses:
129
+ - MIT
130
+ metadata:
131
+ allowed_push_host: https://rubygems.org
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubyforge_project:
148
+ rubygems_version: 2.7.6
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: ServerComponent support for Rails
152
+ test_files: []