neutron-ruby-electron 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 +7 -0
- data/.gitignore +12 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +125 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/neutron +48 -0
- data/bin/setup +8 -0
- data/lib/neutron/app.rb +27 -0
- data/lib/neutron/controller.rb +145 -0
- data/lib/neutron/generator.rb +77 -0
- data/lib/neutron/neutron_npm_package/index.js +128 -0
- data/lib/neutron/neutron_npm_package/package.json +23 -0
- data/lib/neutron/template/LICENSE.txt.tt +21 -0
- data/lib/neutron/template/README.md.tt +3 -0
- data/lib/neutron/template/Rakefile.tt +94 -0
- data/lib/neutron/template/src/Gemfile.tt +7 -0
- data/lib/neutron/template/src/assets/index.html.tt +27 -0
- data/lib/neutron/template/src/assets/javascripts/components/neutron_entry_point_component.js.tt +22 -0
- data/lib/neutron/template/src/assets/javascripts/components/sum.js +36 -0
- data/lib/neutron/template/src/assets/javascripts/neutron.js.tt +23 -0
- data/lib/neutron/template/src/assets/stylesheets/neutron.less.tt +4 -0
- data/lib/neutron/template/src/backend.rb.tt +9 -0
- data/lib/neutron/template/src/main.rb.tt +11 -0
- data/lib/neutron/template/src/main_window.js.tt +40 -0
- data/lib/neutron/version.rb +3 -0
- data/neutron.gemspec +38 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7b94b9dba9d64ca5279b5b46edaaa489678eb8fd
|
4
|
+
data.tar.gz: 15f706d8e6bd8744117795b0af8bacf34fadc4c2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4710ac1b334f0bc28a47bf4c62a266b34016bf1a21b90e127e0a5542e1dbee4dcee2c3d14f3b48337faefc854f06ed07766fdb9c334a20fd8d094fb12ed52dc8
|
7
|
+
data.tar.gz: ffc603482d038a546562ad1983353b899303074947277778aec85969e8534b5517d64863d97767807eb53f0df2bdd80fcb5166984e3b38e68fa4b7e10d24abab
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 pioz
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# Neutron
|
2
|
+
|
3
|
+
Neutron is a mini framework to build desktop app with [Electron](https://electron.atom.io/) and [Ruby](https://www.ruby-lang.org/).
|
4
|
+
Neutron follow the pattern `MVC` where the `V` is handled by Electron and (if you want) [ReactJS](https://facebook.github.io/react/).
|
5
|
+
The `MC` can be handled with pure Ruby code.
|
6
|
+
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Install it yourself as:
|
11
|
+
|
12
|
+
$ gem install neutron-ruby-electron
|
13
|
+
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
First of all generate a new Neutron project:
|
18
|
+
|
19
|
+
$ neutron project_name
|
20
|
+
|
21
|
+
It will generate a new folder with the follow tree
|
22
|
+
```
|
23
|
+
.
|
24
|
+
├── LICENSE.txt
|
25
|
+
├── README.md
|
26
|
+
└── src
|
27
|
+
├── Gemfile
|
28
|
+
├── Gemfile.lock
|
29
|
+
├── assets
|
30
|
+
│ ├── index.html
|
31
|
+
│ ├── javascripts
|
32
|
+
│ │ ├── components
|
33
|
+
│ │ │ └── neutron_entry_point_component.js
|
34
|
+
│ │ └── neutron.js
|
35
|
+
│ └── stylesheets
|
36
|
+
├── backend.rb
|
37
|
+
├── main.rb
|
38
|
+
├── main_window.js
|
39
|
+
├── node_modules/
|
40
|
+
└── package.json
|
41
|
+
```
|
42
|
+
You can run the just generated app with the command:
|
43
|
+
|
44
|
+
$ cd project_name/src
|
45
|
+
$ ruby main.rb
|
46
|
+
|
47
|
+
- The `main.rb` is the main of your app.
|
48
|
+
- The `main_window.js` is the Electron entry point file where the [Electron app](https://electron.atom.io/docs/api/app/) and the [main browser window](https://electron.atom.io/docs/api/browser-window/) are created.
|
49
|
+
- The `backend.rb` is a Ruby class where you can add your instance methods that can be called from the view, from your React components of your Javascript code. This class extends `Neutron::Controller` and looks like this:
|
50
|
+
```
|
51
|
+
class MyController < Neutron::Controller
|
52
|
+
def ping
|
53
|
+
return 'pong'
|
54
|
+
end
|
55
|
+
|
56
|
+
def add(a, b)
|
57
|
+
return(a + b)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
- The `neutron_entry_point_component.js` is the main component that render all your application.
|
62
|
+
|
63
|
+
|
64
|
+
### Communication between Electron and Ruby
|
65
|
+
|
66
|
+
Inside a React component you can import the Neutron module with
|
67
|
+
|
68
|
+
import neutron from 'neutron'
|
69
|
+
|
70
|
+
and use neutron to call a controller method like this:
|
71
|
+
|
72
|
+
neutron.send('method_name', [params], options).then((result) => {...}).catch((error) => {...})
|
73
|
+
|
74
|
+
You can call a Ruby Controller method with `neutron.send` method that return a JS promise with the return value of the method or an error.
|
75
|
+
|
76
|
+
For example you can have a component like this:
|
77
|
+
```
|
78
|
+
import React from 'react'
|
79
|
+
import neutron from 'neutron'
|
80
|
+
|
81
|
+
export default class Sum extends React.Component {
|
82
|
+
|
83
|
+
constructor(props) {
|
84
|
+
super(props)
|
85
|
+
this.state = {}
|
86
|
+
}
|
87
|
+
|
88
|
+
sum() {
|
89
|
+
const a = parseInt(this.a.value)
|
90
|
+
const b = parseInt(this.b.value)
|
91
|
+
neutron.send('add', [a, b]).then((result) => {
|
92
|
+
this.setState({result: result})
|
93
|
+
}).catch((error) => {
|
94
|
+
console.log(error)
|
95
|
+
})
|
96
|
+
}
|
97
|
+
|
98
|
+
render() {
|
99
|
+
return(
|
100
|
+
<div>
|
101
|
+
<p>
|
102
|
+
<input ref={(input) => this.a = input}/>
|
103
|
+
+
|
104
|
+
<input ref={(input) => this.b = input}/>
|
105
|
+
= {this.state.result}
|
106
|
+
</p>
|
107
|
+
<p>
|
108
|
+
<button onClick={this.sum.bind(this)}>Calculate</button>
|
109
|
+
</p>
|
110
|
+
</div>
|
111
|
+
)
|
112
|
+
}
|
113
|
+
}
|
114
|
+
```
|
115
|
+
In this componenet the sum is calculated by the method `add` in the Ruby controller.
|
116
|
+
|
117
|
+
|
118
|
+
## Contributing
|
119
|
+
|
120
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pioz/neutron.
|
121
|
+
|
122
|
+
|
123
|
+
## License
|
124
|
+
|
125
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "neutron"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/neutron
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'neutron/version'
|
5
|
+
require 'neutron/generator'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
def parse_args(args)
|
9
|
+
options = {react: true, jquery: false, bootstrap: true, development: false, debug: false}
|
10
|
+
opt_parser = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: neutron [options] PROJECT_NAME"
|
12
|
+
opts.separator ''
|
13
|
+
opts.separator 'Options:'
|
14
|
+
opts.on('-r', '--[no-]react', 'Create a project with ReactJS support') do |opt|
|
15
|
+
options[:react] = opt
|
16
|
+
end
|
17
|
+
opts.on('-j', '--[no-]jquery', 'Create a project with jQuery support') do |opt|
|
18
|
+
options[:jquery] = opt
|
19
|
+
end
|
20
|
+
opts.on('-b', '--[no-]bootstrap', 'Create a project with Twitter Bootstrap support') do |opt|
|
21
|
+
options[:bootstrap] = opt
|
22
|
+
end
|
23
|
+
opts.on_tail('--dev-mode', 'Development mode') do |opt|
|
24
|
+
options[:development] = opt
|
25
|
+
end
|
26
|
+
opts.on_tail('-d', '--[no-]debug', 'Debug mode') do |opt|
|
27
|
+
options[:debug] = opt
|
28
|
+
end
|
29
|
+
opts.on_tail('-v', '--version', 'Print Neutron version') do
|
30
|
+
puts Neutron::VERSION
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
opts.on_tail('-h', '--help', 'Help') do
|
34
|
+
puts opts
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
end
|
38
|
+
opt_parser.parse!(args)
|
39
|
+
if args.size != 1
|
40
|
+
puts opt_parser.help
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
options[:path] = args.first
|
44
|
+
options[:name] = File.basename(options[:path])
|
45
|
+
return options
|
46
|
+
end
|
47
|
+
|
48
|
+
Neutron::Generator.new(parse_args(ARGV)).generate!
|
data/bin/setup
ADDED
data/lib/neutron/app.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'sys/proctable'
|
2
|
+
|
3
|
+
module Neutron
|
4
|
+
|
5
|
+
class App
|
6
|
+
|
7
|
+
def initialize(controller:)
|
8
|
+
raise 'Controller must be inherit from Neutron::Controller' unless controller.is_a?(::Neutron::Controller)
|
9
|
+
@controller = controller
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
path = File.expand_path('..', caller[0].split(':').first)
|
14
|
+
begin
|
15
|
+
Thread.new { @controller.run }
|
16
|
+
`cd '#{path}' && npm run boot`
|
17
|
+
ensure
|
18
|
+
process_path = File.join(path, 'node_modules/electron-prebuilt-compile/lib/es6-init.js')
|
19
|
+
p = Sys::ProcTable.ps.select { |p| p.cmdline.include?(process_path) }.first
|
20
|
+
Process.kill('HUP', p.pid) if p
|
21
|
+
@controller.stop
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Neutron
|
5
|
+
|
6
|
+
Thread.abort_on_exception = true
|
7
|
+
|
8
|
+
class Controller < UNIXServer
|
9
|
+
|
10
|
+
def initialize(path = '/tmp/neutron.sock')
|
11
|
+
File.delete(path) if File.exists?(path)
|
12
|
+
|
13
|
+
super(path)
|
14
|
+
@path = path
|
15
|
+
@run = true
|
16
|
+
|
17
|
+
trap('INT') do
|
18
|
+
STDOUT.puts 'Closing socket...'
|
19
|
+
self.stop
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def stop
|
24
|
+
@run = false
|
25
|
+
self.close
|
26
|
+
File.delete(@path) if File.exists?(@path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
while @run do
|
31
|
+
begin
|
32
|
+
Thread.fork(self.accept) do |sock| # begin
|
33
|
+
Thread.current[:threads] = {}
|
34
|
+
while (data = sock.gets)
|
35
|
+
break if data.empty?
|
36
|
+
data.chop!
|
37
|
+
# STDOUT.puts data
|
38
|
+
Thread.fork(sock, data, Thread.current[:threads]) do |sock, data, threads|
|
39
|
+
Thread.current[:sock] = sock
|
40
|
+
Thread.current[:threads] = threads
|
41
|
+
response = dispatch(data)
|
42
|
+
if response
|
43
|
+
send_string(sock, response.to_json + "\n")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
rescue Errno::EBADF
|
49
|
+
# socket has been closed and server is waiting on socket.accept
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def notify(event, result = nil)
|
55
|
+
if result.is_a?(Hash) && result[:error].is_a?(Hash)
|
56
|
+
result[:error][:code] ||= SERVER_ERROR
|
57
|
+
result[:error][:message] ||= 'Server error'
|
58
|
+
response = {jsonrpc: '2.0', error: result[:error], event: event, id: -1}
|
59
|
+
else
|
60
|
+
response = {jsonrpc: '2.0', result: result, event: event, id: -1}
|
61
|
+
end
|
62
|
+
sock = Thread.current[:sock]
|
63
|
+
if sock
|
64
|
+
send_string(sock, response.to_json + "\n")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
PARSE_ERROR = -32700
|
69
|
+
INVALID_REQUEST = -32600
|
70
|
+
METHOD_NOT_FOUND = -32601
|
71
|
+
INTERNAL_ERROR = -32603
|
72
|
+
SERVER_ERROR = -32000
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def run_thread(&block)
|
77
|
+
#c = caller[0][/`.*'/][1..-2].to_sym
|
78
|
+
callers = caller.map{|c| c[/`.*'/][1..-2].to_sym}
|
79
|
+
c = callers.select{|c| Thread.current[:threads].keys.include?(c)}.first
|
80
|
+
sock = Thread.current[:sock]
|
81
|
+
Thread.current[:threads][c] << Thread.fork do
|
82
|
+
Thread.current[:sock] = sock
|
83
|
+
block.call
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def send_string(sock, s)
|
90
|
+
while(s.length > 0)
|
91
|
+
sent = sock.send(s, 0)
|
92
|
+
s = s[sent..-1]
|
93
|
+
end
|
94
|
+
sock.flush
|
95
|
+
end
|
96
|
+
|
97
|
+
def dispatch(data)
|
98
|
+
begin
|
99
|
+
jsonrpc = JSON.parse(data)
|
100
|
+
rescue JSON::ParserError
|
101
|
+
return {jsonrpc: '2.0', error: {code: PARSE_ERROR, message: 'Parse error'}, id: nil}
|
102
|
+
end
|
103
|
+
if jsonrpc['jsonrpc'] != '2.0' || !jsonrpc['id'].is_a?(Integer) || jsonrpc['id'] < 0
|
104
|
+
return {jsonrpc: '2.0', error: {code: INVALID_REQUEST, message: 'Invalid request'}, id: jsonrpc['id']}
|
105
|
+
end
|
106
|
+
if !self.respond_to?(jsonrpc['method'])
|
107
|
+
return {jsonrpc: '2.0', error: {code: METHOD_NOT_FOUND, message: 'Method not found'}, id: jsonrpc['id']}
|
108
|
+
end
|
109
|
+
|
110
|
+
# begin
|
111
|
+
# result = run_method(jsonrpc['method'], jsonrpc['params'], once: jsonrpc['once'])
|
112
|
+
# rescue Exception => e
|
113
|
+
# return {jsonrpc: '2.0', error: {code: INTERNAL_ERROR, message: e.message}, id: jsonrpc['id']}
|
114
|
+
# end
|
115
|
+
result = run_method(jsonrpc['method'], jsonrpc['params'], once: jsonrpc['once'])
|
116
|
+
|
117
|
+
if result.is_a?(Hash) && result[:error].is_a?(Hash)
|
118
|
+
result[:error][:code] ||= SERVER_ERROR
|
119
|
+
result[:error][:message] ||= 'Server error'
|
120
|
+
return {jsonrpc: '2.0', error: result[:error], event: jsonrpc['method'], id: jsonrpc['id']}
|
121
|
+
else
|
122
|
+
r = result.is_a?(Hash) && !result[:result].nil? ? result[:result] : result
|
123
|
+
# Reply with a non error result
|
124
|
+
return {jsonrpc: '2.0', result: r, event: jsonrpc['method'], id: jsonrpc['id']}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def run_method(method, params, once: true)
|
129
|
+
if once
|
130
|
+
Thread.current[:threads][method.to_sym] ||= []
|
131
|
+
Thread.current[:threads][method.to_sym].each do |t|
|
132
|
+
t.kill if t.alive?
|
133
|
+
Thread.current[:threads][method.to_sym].delete(t)
|
134
|
+
end
|
135
|
+
Thread.current[:threads][method.to_sym] << Thread.current
|
136
|
+
end
|
137
|
+
if params
|
138
|
+
return self.__send__(method, *params)
|
139
|
+
else
|
140
|
+
return self.__send__(method)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'json'
|
3
|
+
require 'etc'
|
4
|
+
|
5
|
+
|
6
|
+
module Neutron
|
7
|
+
|
8
|
+
TEMPLATE_PATH = File.expand_path('../template', __FILE__)
|
9
|
+
NEUTRON_NPM_PACKAGE_PATH = File.expand_path('../neutron_npm_package', __FILE__)
|
10
|
+
|
11
|
+
class Generator < Thor::Group
|
12
|
+
include Thor::Actions
|
13
|
+
|
14
|
+
def initialize(options)
|
15
|
+
super()
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.source_root
|
20
|
+
File.dirname(__FILE__)
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate!
|
24
|
+
self.copy_template
|
25
|
+
self.generate_package_json
|
26
|
+
end
|
27
|
+
|
28
|
+
def copy_template
|
29
|
+
directory(TEMPLATE_PATH, options[:path], exclude_pattern: /components/)
|
30
|
+
if options[:react]
|
31
|
+
directory(File.join(TEMPLATE_PATH, 'src/assets/javascripts/components'), File.join(options[:path], 'src/assets/javascripts/components'))
|
32
|
+
end
|
33
|
+
inside(File.join(options[:path], 'src')) do
|
34
|
+
system 'bundle install'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_package_json
|
39
|
+
say_status :generate, File.join(options[:path], 'src', 'package.json')
|
40
|
+
inside(File.join(options[:path], 'src')) do
|
41
|
+
# Init NPM
|
42
|
+
`npm init -y`
|
43
|
+
# Install local neutron npm package
|
44
|
+
system "npm install --save-dev #{NEUTRON_NPM_PACKAGE_PATH}"
|
45
|
+
# Install NPM packages
|
46
|
+
%w(electron electron-prebuilt-compile).each do |package|
|
47
|
+
system "npm install --save-dev #{package}"
|
48
|
+
end
|
49
|
+
if options[:jquery] || options[:bootstrap]
|
50
|
+
system "npm install --save jquery"
|
51
|
+
end
|
52
|
+
if options[:bootstrap]
|
53
|
+
system "npm install --save bootstrap"
|
54
|
+
end
|
55
|
+
if options[:react]
|
56
|
+
system "npm install --save react"
|
57
|
+
system "npm install --save react-dom"
|
58
|
+
end
|
59
|
+
# Edit package.json
|
60
|
+
username = Etc.getlogin.downcase
|
61
|
+
json = JSON.parse(File.read('package.json'))
|
62
|
+
json['name'] = options[:name]
|
63
|
+
json['description'] = 'Another Neutron app'
|
64
|
+
json['repository'] = "https://github.com/#{username}/#{options[:name]}"
|
65
|
+
json['author'] = username
|
66
|
+
json['license'] = 'MIT'
|
67
|
+
json['main'] = 'main_window.js'
|
68
|
+
json['scripts']['boot'] = './node_modules/.bin/electron .'
|
69
|
+
json['scripts']['buildjs'] = 'NODE_ENV=production ./node_modules/.bin/electron-compile .'
|
70
|
+
#json['babel'] = {'presets' => ['es2015']}
|
71
|
+
File.open('package.json', 'w') {|f| f << json.to_json}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
// import Events from 'events'
|
2
|
+
// import net from 'net'
|
3
|
+
const Events = require('events')
|
4
|
+
const net = require('net')
|
5
|
+
|
6
|
+
|
7
|
+
let global_jsonrpc_id = 1
|
8
|
+
|
9
|
+
|
10
|
+
class Neutron extends Events.EventEmitter {
|
11
|
+
|
12
|
+
constructor(path = '/tmp/neutron.sock') {
|
13
|
+
super()
|
14
|
+
this.setMaxListeners(0)
|
15
|
+
this.promises = {}
|
16
|
+
this.path = path
|
17
|
+
this.socket = new net.Socket()
|
18
|
+
this.msg = ''
|
19
|
+
|
20
|
+
this.socket.on('data', (data) => {
|
21
|
+
const s = data.toString()
|
22
|
+
this.msg += s
|
23
|
+
if (s[s.length-1] === "\n") {
|
24
|
+
const msg = this.msg.slice(0, -1)
|
25
|
+
this.msg = ''
|
26
|
+
const messages = msg.split("\n")
|
27
|
+
for (let i = 0; i < messages.length; i++) {
|
28
|
+
try {
|
29
|
+
const jsonrpc = JSON.parse(messages[i])
|
30
|
+
if (typeof(jsonrpc['id']) !== 'number') {
|
31
|
+
this.emit('err', {message: 'Missing id on jsonrpc reply'})
|
32
|
+
this.emit('all')
|
33
|
+
} else {
|
34
|
+
if (jsonrpc['error']) {
|
35
|
+
const error = jsonrpc['error']
|
36
|
+
error.toString = () => {
|
37
|
+
this.message
|
38
|
+
}
|
39
|
+
if (jsonrpc['event'])
|
40
|
+
this.emit(`err-${jsonrpc['event']}`, error)
|
41
|
+
this.emit(`err-${jsonrpc['id']}`, error)
|
42
|
+
this.emit('all')
|
43
|
+
} else {
|
44
|
+
if (jsonrpc['event'])
|
45
|
+
this.emit(jsonrpc['event'], jsonrpc['result'])
|
46
|
+
this.emit(`json-${jsonrpc['id']}`, jsonrpc['result'])
|
47
|
+
this.emit('all')
|
48
|
+
}
|
49
|
+
}
|
50
|
+
} catch(error) {
|
51
|
+
this.emit('err', {message: 'Error to parse the response'})
|
52
|
+
this.emit('all')
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
})
|
57
|
+
|
58
|
+
this.socket.on('connect', () => {
|
59
|
+
this.emit('connect')
|
60
|
+
this.emit('all')
|
61
|
+
})
|
62
|
+
|
63
|
+
this.socket.on('end', () => {
|
64
|
+
this.emit('end')
|
65
|
+
this.emit('all')
|
66
|
+
this.reconnect(2000)
|
67
|
+
})
|
68
|
+
|
69
|
+
this.socket.on('error', (error) => {
|
70
|
+
this.emit('err-connection', error)
|
71
|
+
this.emit('err', error)
|
72
|
+
this.emit('all')
|
73
|
+
this.reconnect(2000)
|
74
|
+
})
|
75
|
+
}
|
76
|
+
|
77
|
+
connect() {
|
78
|
+
// remote.process.on('uncaughtException', (error) => {
|
79
|
+
// this.emit('connection-error', error)
|
80
|
+
// this.emit('all')
|
81
|
+
// this.emit('all-errors')
|
82
|
+
// this.reconnect(2000)
|
83
|
+
// })
|
84
|
+
this.socket.connect({path: this.path})
|
85
|
+
}
|
86
|
+
|
87
|
+
reconnect(timeout = 0) {
|
88
|
+
setTimeout(() => {
|
89
|
+
console.log('Try to reconnect to the socket ' + this.path + '...')
|
90
|
+
this.socket.end()
|
91
|
+
this.socket.connect({path: this.path})
|
92
|
+
}, timeout)
|
93
|
+
}
|
94
|
+
|
95
|
+
close() {
|
96
|
+
this.socket.end()
|
97
|
+
}
|
98
|
+
|
99
|
+
real_send(method, params, {once = true} = {}) {
|
100
|
+
const id = global_jsonrpc_id++
|
101
|
+
this.socket.write(JSON.stringify({
|
102
|
+
jsonrpc: '2.0',
|
103
|
+
method: method,
|
104
|
+
params: params,
|
105
|
+
once: once,
|
106
|
+
id: id
|
107
|
+
}) + "\n")
|
108
|
+
return id
|
109
|
+
}
|
110
|
+
|
111
|
+
send(method, params, {once = true} = {}) {
|
112
|
+
const id = this.real_send(method, params, {once: once})
|
113
|
+
return new Promise((resolve, reject) => {
|
114
|
+
this.on(`json-${id}`, resolve)
|
115
|
+
this.on(`err-${id}`, reject)
|
116
|
+
this.on('err', reject)
|
117
|
+
})
|
118
|
+
}
|
119
|
+
|
120
|
+
}
|
121
|
+
|
122
|
+
const neutron = new Neutron()
|
123
|
+
neutron.on('connect', () => {
|
124
|
+
console.log('Electron connected to Ruby!')
|
125
|
+
})
|
126
|
+
neutron.connect()
|
127
|
+
// export default neutron
|
128
|
+
module.exports = neutron
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"name": "neutron",
|
3
|
+
"version": "0.1.0",
|
4
|
+
"description": "Mini framework to build desktop app with Electron and Ruby",
|
5
|
+
"main": "index.js",
|
6
|
+
"scripts": {
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
8
|
+
},
|
9
|
+
"repository": {
|
10
|
+
"type": "git",
|
11
|
+
"url": "git+https://github.com/pioz/neutron.git"
|
12
|
+
},
|
13
|
+
"keywords": [
|
14
|
+
"ruby",
|
15
|
+
"electron"
|
16
|
+
],
|
17
|
+
"author": "pioz",
|
18
|
+
"license": "MIT",
|
19
|
+
"bugs": {
|
20
|
+
"url": "https://github.com/pioz/neutron/issues"
|
21
|
+
},
|
22
|
+
"homepage": "https://github.com/pioz/neutron#readme"
|
23
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) <%= Time.now.year %> <%= Etc.getlogin.downcase %>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
PACKAGE_NAME = '<%= options[:name] %>'
|
4
|
+
VERSION = '0.1.0'
|
5
|
+
RUBY_V = '2.2'
|
6
|
+
TRAVELING_RUBY_VERSION = "20150715-#{RUBY_V}.2"
|
7
|
+
|
8
|
+
desc 'Package your app'
|
9
|
+
task package: ['package:linux:x86', 'package:linux:x86_64', 'package:osx']
|
10
|
+
|
11
|
+
namespace :package do
|
12
|
+
namespace :linux do
|
13
|
+
desc 'Package your app for Linux x86'
|
14
|
+
task :x86 => "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86.tar.gz" do
|
15
|
+
create_package('linux-x86')
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Package your app for Linux x86_64'
|
19
|
+
task :x86_64 => "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86_64.tar.gz" do
|
20
|
+
create_package('linux-x86_64')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Package your app for OS X'
|
25
|
+
task :osx do
|
26
|
+
create_package('osx')
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_package(target)
|
32
|
+
if RUBY_VERSION !~ /^#{RUBY_V}\./
|
33
|
+
abort "You can only use Ruby #{RUBY_V}, because that's what Traveling Ruby uses."
|
34
|
+
end
|
35
|
+
package_dir = "#{PACKAGE_NAME}-#{VERSION}-#{target}"
|
36
|
+
sh "rm -rf #{package_dir}"
|
37
|
+
sh "rm -rf tmp/"
|
38
|
+
sh "mkdir tmp"
|
39
|
+
sh "mkdir -p #{package_dir}/lib/ruby"
|
40
|
+
sh "rsync -a src #{package_dir}/lib"
|
41
|
+
download_runtime('osx')
|
42
|
+
sh "tar -xzf tmp/traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{target}.tar.gz -C #{package_dir}/lib/ruby"
|
43
|
+
create_wrapper("#{package_dir}/#{PACKAGE_NAME}")
|
44
|
+
sh "chmod 755 #{package_dir}/#{PACKAGE_NAME}"
|
45
|
+
bundle_install
|
46
|
+
sh "cp -pR tmp/vendor #{package_dir}/lib/"
|
47
|
+
sh "cp src/Gemfile src/Gemfile.lock #{package_dir}/lib/vendor/"
|
48
|
+
sh "mkdir #{package_dir}/lib/vendor/.bundle"
|
49
|
+
sh "cp tmp/bundler-config #{package_dir}/lib/vendor/.bundle/config"
|
50
|
+
if !ENV['DIR_ONLY']
|
51
|
+
sh "tar -czf #{package_dir}.tar.gz #{package_dir}"
|
52
|
+
sh "rm -rf #{package_dir}"
|
53
|
+
end
|
54
|
+
sh "rm -rf tmp/"
|
55
|
+
end
|
56
|
+
|
57
|
+
def download_runtime(target)
|
58
|
+
sh "cd tmp && curl -L -O --fail https://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{target}.tar.gz"
|
59
|
+
end
|
60
|
+
|
61
|
+
def bundle_install
|
62
|
+
sh "cp src/Gemfile src/Gemfile.lock tmp/"
|
63
|
+
Bundler.with_clean_env do
|
64
|
+
sh "cd tmp && env BUNDLE_IGNORE_CONFIG=1 bundle install --path vendor --without development"
|
65
|
+
<% if options[:development] -%>
|
66
|
+
sh "cd tmp && env BUNDLE_IGNORE_CONFIG=1 bundle package --all"
|
67
|
+
sh "mv tmp/vendor/cache/neutron tmp/vendor/ruby/#{RUBY_V}.0/gems"
|
68
|
+
<% end -%>
|
69
|
+
end
|
70
|
+
sh "rm -rf tmp/vendor/cache"
|
71
|
+
sh "rm -rf tmp/vendor/ruby/#{RUBY_V}.0/cache"
|
72
|
+
bundle_config = <<-CONFIG
|
73
|
+
BUNDLE_PATH: .
|
74
|
+
BUNDLE_WITHOUT: development
|
75
|
+
BUNDLE_DISABLE_SHARED_GEMS: '1'
|
76
|
+
CONFIG
|
77
|
+
File.open('tmp/bundler-config', 'w') {|f| f << bundle_config.gsub(/^\s{4}/, '') }
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_wrapper(out)
|
81
|
+
wrapper = <<-WRAPPER
|
82
|
+
#!/bin/bash
|
83
|
+
set -e
|
84
|
+
|
85
|
+
SELFDIR="`dirname \"$0\"`"
|
86
|
+
SELFDIR="`cd \"$SELFDIR\" && pwd`"
|
87
|
+
|
88
|
+
export BUNDLE_GEMFILE="$SELFDIR/lib/vendor/Gemfile"
|
89
|
+
unset BUNDLE_IGNORE_CONFIG
|
90
|
+
|
91
|
+
exec "NODE_ENV=production $SELFDIR/lib/ruby/bin/ruby" -rbundler/setup "$SELFDIR/lib/src/main.rb"
|
92
|
+
WRAPPER
|
93
|
+
File.open(out, 'w') {|f| f << wrapper.gsub(/^\s{4}/, '') }
|
94
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<script src='./javascripts/neutron.js'></script>
|
4
|
+
<link href='./stylesheets/neutron.less' type='text/less' rel='stylesheet'>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<% if options[:react] -%>
|
8
|
+
<div id='react-entry-point'></div>
|
9
|
+
<script>
|
10
|
+
ReactDOM.render(React.createElement(NeutronEntryPointComponent, null), document.getElementById('react-entry-point'))
|
11
|
+
</script>
|
12
|
+
<% else -%>
|
13
|
+
<div>
|
14
|
+
<h2>Welcome to NEUTRON</h2>
|
15
|
+
<p>
|
16
|
+
<button id='b'>Try Neutron</button>
|
17
|
+
<script>
|
18
|
+
document.getElementById('b').addEventListener('click', () => {
|
19
|
+
for(let i = 0; i < 10; i++)
|
20
|
+
neutron.send('add', [0, i], {once: false}).then(result => console.log(result)).catch(e => console.log(e))
|
21
|
+
})
|
22
|
+
</script>
|
23
|
+
</p>
|
24
|
+
</div>
|
25
|
+
<% end -%>
|
26
|
+
</body>
|
27
|
+
</html>
|
data/lib/neutron/template/src/assets/javascripts/components/neutron_entry_point_component.js.tt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import neutron from 'neutron'
|
3
|
+
|
4
|
+
export default class NeutronEntryPointComponent extends React.Component {
|
5
|
+
|
6
|
+
button_click() {
|
7
|
+
for(let i = 0; i < 10; i++)
|
8
|
+
neutron.send('add', [0, i], {once: false}).then(result => console.log(result)).catch(e => console.log(e))
|
9
|
+
}
|
10
|
+
|
11
|
+
render() {
|
12
|
+
return(
|
13
|
+
<div>
|
14
|
+
<h2>Welcome to NEUTRON</h2>
|
15
|
+
<p>
|
16
|
+
<button className='btn btn-default' onClick={this.button_click}>Try Neutron</button>
|
17
|
+
</p>
|
18
|
+
</div>
|
19
|
+
)
|
20
|
+
}
|
21
|
+
|
22
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import neutron from 'neutron'
|
3
|
+
|
4
|
+
export default class Sum extends React.Component {
|
5
|
+
|
6
|
+
constructor(props) {
|
7
|
+
super(props)
|
8
|
+
this.state = {}
|
9
|
+
}
|
10
|
+
|
11
|
+
sum() {
|
12
|
+
const a = parseInt(this.a.value)
|
13
|
+
const b = parseInt(this.b.value)
|
14
|
+
neutron.send('add', [a, b]).then((result) => {
|
15
|
+
this.setState({result: result})
|
16
|
+
}).catch((error) => {
|
17
|
+
console.log(error)
|
18
|
+
})
|
19
|
+
}
|
20
|
+
|
21
|
+
render() {
|
22
|
+
return(
|
23
|
+
<div>
|
24
|
+
<p>
|
25
|
+
<input ref={(input) => this.a = input}/>
|
26
|
+
+
|
27
|
+
<input ref={(input) => this.b = input}/>
|
28
|
+
= {this.state.result}
|
29
|
+
</p>
|
30
|
+
<p>
|
31
|
+
<button onClick={this.sum.bind(this)}>Calculate</button>
|
32
|
+
</p>
|
33
|
+
</div>
|
34
|
+
)
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<% if options[:jquery] || options[:bootstrap] -%>
|
2
|
+
import jQuery from 'jquery'
|
3
|
+
<% end -%>
|
4
|
+
<% if options[:react] -%>
|
5
|
+
import ReactDOM from 'react-dom'
|
6
|
+
import React from 'react'
|
7
|
+
import NeutronEntryPointComponent from './javascripts/components/neutron_entry_point_component'
|
8
|
+
<% else -%>
|
9
|
+
import neutron from 'neutron'
|
10
|
+
<% end -%>
|
11
|
+
<% if options[:jquery] || options[:bootstrap] -%>
|
12
|
+
window.jQuery = window.$ = jQuery
|
13
|
+
<% end -%>
|
14
|
+
<% if options[:react] -%>
|
15
|
+
window.ReactDOM = ReactDOM
|
16
|
+
window.React = React
|
17
|
+
window.NeutronEntryPointComponent = NeutronEntryPointComponent
|
18
|
+
<% else -%>
|
19
|
+
window.neutron = neutron
|
20
|
+
<% end -%>
|
21
|
+
<% if options[:bootstrap] -%>
|
22
|
+
require('bootstrap')
|
23
|
+
<% end -%>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% if options[:development] -%>
|
2
|
+
require 'bundler'
|
3
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __FILE__)
|
4
|
+
Bundler.require
|
5
|
+
|
6
|
+
<% end -%>
|
7
|
+
require 'neutron/app'
|
8
|
+
require File.expand_path('../backend.rb', __FILE__)
|
9
|
+
|
10
|
+
app = Neutron::App.new(controller: Backend.new)
|
11
|
+
app.run
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { app, BrowserWindow } from 'electron'
|
2
|
+
import { enableLiveReload } from 'electron-compile'
|
3
|
+
import path from 'path'
|
4
|
+
import url from 'url'
|
5
|
+
|
6
|
+
if (process.env.NODE_ENV !== 'production')
|
7
|
+
enableLiveReload()
|
8
|
+
|
9
|
+
let win = null
|
10
|
+
|
11
|
+
function createWindow() {
|
12
|
+
win = new BrowserWindow({title: 'Another Neutron app', width: 800, height: 600})
|
13
|
+
win.loadURL(url.format({
|
14
|
+
pathname: path.join(__dirname, 'assets/index.html'),
|
15
|
+
protocol: 'file:',
|
16
|
+
slashes: true
|
17
|
+
}))
|
18
|
+
if (process.env.NODE_ENV !== 'production')
|
19
|
+
win.webContents.openDevTools()
|
20
|
+
win.on('close', (event) => {
|
21
|
+
if (app.quitting)
|
22
|
+
win = null
|
23
|
+
else {
|
24
|
+
event.preventDefault()
|
25
|
+
win.hide()
|
26
|
+
}
|
27
|
+
})
|
28
|
+
}
|
29
|
+
|
30
|
+
app.on('ready', createWindow)
|
31
|
+
|
32
|
+
app.on('window-all-closed', () => {
|
33
|
+
if (process.platform !== 'darwin') {
|
34
|
+
app.quit()
|
35
|
+
}
|
36
|
+
})
|
37
|
+
|
38
|
+
app.on('activate', () => { win.show() })
|
39
|
+
|
40
|
+
app.on('before-quit', () => app.quitting = true)
|
data/neutron.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'neutron/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "neutron-ruby-electron"
|
8
|
+
spec.version = Neutron::VERSION
|
9
|
+
spec.authors = ["pioz"]
|
10
|
+
spec.email = ["epilotto@gmx.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Mini framework to build desktop app with Electron and Ruby}
|
13
|
+
spec.description = %q{Mini framework to build desktop app with Electron and Ruby}
|
14
|
+
spec.homepage = "https://github.com/pioz/neutron"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org/"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
+
"public gem pushes."
|
24
|
+
end
|
25
|
+
|
26
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
f.match(%r{^(test|spec|features)/})
|
28
|
+
end
|
29
|
+
spec.bindir = "bin"
|
30
|
+
spec.executables = ["neutron"]
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
+
|
36
|
+
spec.add_runtime_dependency "thor", "~> 0.19"
|
37
|
+
spec.add_runtime_dependency "sys-proctable", "~> 1.1"
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: neutron-ruby-electron
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- pioz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.19'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.19'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sys-proctable
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
description: Mini framework to build desktop app with Electron and Ruby
|
70
|
+
email:
|
71
|
+
- epilotto@gmx.com
|
72
|
+
executables:
|
73
|
+
- neutron
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/console
|
83
|
+
- bin/neutron
|
84
|
+
- bin/setup
|
85
|
+
- lib/neutron/app.rb
|
86
|
+
- lib/neutron/controller.rb
|
87
|
+
- lib/neutron/generator.rb
|
88
|
+
- lib/neutron/neutron_npm_package/index.js
|
89
|
+
- lib/neutron/neutron_npm_package/package.json
|
90
|
+
- lib/neutron/template/LICENSE.txt.tt
|
91
|
+
- lib/neutron/template/README.md.tt
|
92
|
+
- lib/neutron/template/Rakefile.tt
|
93
|
+
- lib/neutron/template/src/Gemfile.tt
|
94
|
+
- lib/neutron/template/src/assets/index.html.tt
|
95
|
+
- lib/neutron/template/src/assets/javascripts/components/neutron_entry_point_component.js.tt
|
96
|
+
- lib/neutron/template/src/assets/javascripts/components/sum.js
|
97
|
+
- lib/neutron/template/src/assets/javascripts/neutron.js.tt
|
98
|
+
- lib/neutron/template/src/assets/stylesheets/neutron.less.tt
|
99
|
+
- lib/neutron/template/src/backend.rb.tt
|
100
|
+
- lib/neutron/template/src/main.rb.tt
|
101
|
+
- lib/neutron/template/src/main_window.js.tt
|
102
|
+
- lib/neutron/version.rb
|
103
|
+
- neutron.gemspec
|
104
|
+
homepage: https://github.com/pioz/neutron
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata:
|
108
|
+
allowed_push_host: https://rubygems.org/
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.6.12
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: Mini framework to build desktop app with Electron and Ruby
|
129
|
+
test_files: []
|