neutron-ruby-electron 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|