mwc 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ require 'mwc/utils/command_registry'
6
+ require 'mwc/config'
7
+ require 'mwc/commands/init'
8
+ require 'mwc/commands/compile'
9
+ require 'mwc/commands/server'
10
+
11
+ module Mwc
12
+ # :nodoc:
13
+ class Command < Thor
14
+ include Utils::CommandRegistry
15
+
16
+ desc 'version', 'show version'
17
+ def version
18
+ puts Mwc::VERSION
19
+ end
20
+
21
+ add_command Commands::Init
22
+ add_command Commands::Compile
23
+ add_command Commands::Server
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor/rake_compat'
4
+
5
+ require 'mwc/utils/command'
6
+ require 'mwc/tasks'
7
+ require 'mwc'
8
+
9
+ module Mwc
10
+ module Commands
11
+ # Compile mruby to wasm
12
+ class Compile < Thor::Group
13
+ include Utils::Command
14
+
15
+ name 'compile'
16
+ description 'compile source code to wasm'
17
+ display_on { Mwc.config.exist? }
18
+ add_option :format, default: 'html', enum: %w[html js wasm]
19
+
20
+ def compile
21
+ Tasks.new
22
+ Rake::Task[parent_options['format']].invoke
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mwc/utils/command'
4
+ require 'mwc'
5
+
6
+ module Mwc
7
+ module Commands
8
+ # Create a new project
9
+ class Init < Thor::Group
10
+ include Thor::Actions
11
+ include Utils::Command
12
+
13
+ name 'init'
14
+ usage 'init NAME'
15
+ description 'create a new project'
16
+ display_on { !Mwc.config.exist? }
17
+ argument :name, type: :string, desc: 'project name'
18
+
19
+ def create_project
20
+ empty_directory(name)
21
+ self.destination_root = name
22
+ Mwc.root = destination_root
23
+ end
24
+
25
+ # :nodoc:
26
+ def create_mwcrc
27
+ template('mwcrc.erb', '.mwcrc')
28
+ end
29
+
30
+ # :nodoc:
31
+ def setup_project
32
+ empty_directory('vendor')
33
+ empty_directory('dist')
34
+ empty_directory('src/js')
35
+ copy_file('config/build.rb')
36
+ copy_file('.gitignore')
37
+ end
38
+
39
+ # :nodoc:
40
+ def download_mruby
41
+ Mwc.config.reload!
42
+ # TODO: Allow choose download mode
43
+ inside(mruby_directory.dirname) do
44
+ run("curl -OL #{archive_url}")
45
+ run("tar -zxf #{filename}")
46
+ remove_file(filename)
47
+ run("mv mruby-#{version} #{mruby_directory}")
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def version
54
+ Mwc.config.mruby.version
55
+ end
56
+
57
+ # :nodoc:
58
+ def archive_url
59
+ "https://github.com/mruby/mruby/archive/#{filename}"
60
+ end
61
+
62
+ # :nodoc:
63
+ def filename
64
+ "#{version}.tar.gz"
65
+ end
66
+
67
+ def mruby_directory
68
+ Mwc.config.mruby.path
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack'
4
+
5
+ require 'mwc/utils/command'
6
+ require 'mwc/server'
7
+ require 'mwc'
8
+
9
+ module Mwc
10
+ module Commands
11
+ # :nodoc:
12
+ class Server < Thor::Group
13
+ include Utils::Command
14
+
15
+ name 'server'
16
+ description 'serve compiled wasm'
17
+ add_option :port, type: :numeric, default: 8080
18
+
19
+ def boot
20
+ Rack::Handler
21
+ .default
22
+ .run(Mwc::Server.new, Port: parent_options['port'])
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mwc'
4
+
5
+ module Mwc
6
+ # The compile options
7
+ class CompileOptions
8
+ # :nodoc:
9
+ EXTRA_JS_TYPE = {
10
+ library_js: '--js-library',
11
+ pre_js: '--pre-js',
12
+ post_js: '--post-js'
13
+ }.freeze
14
+
15
+ OPTIONS = %i[shell source_map extra].freeze
16
+
17
+ # :nodoc:
18
+ def initialize(options = {})
19
+ @options = []
20
+
21
+ options.each do |name, value|
22
+ handler = "add_#{name}"
23
+ send(handler, value) if respond_to?(handler)
24
+ end
25
+
26
+ OPTIONS.each { |name| send("setup_#{name}") }
27
+ output(options[:format])
28
+ end
29
+
30
+ # Setup shell file
31
+ #
32
+ # @since 0.2.0
33
+ # @api private
34
+ def setup_shell
35
+ return if Mwc.config.project.shell.nil?
36
+
37
+ path = Mwc.root.join(Mwc.config.project.shell)
38
+ @options.push "--shell-file #{path}"
39
+ end
40
+
41
+ # Setup source map
42
+ #
43
+ # @since 0.2.0
44
+ # @api private
45
+ def setup_source_map
46
+ return unless Mwc.config.project.source_map
47
+
48
+ @options.push '-g4 --source-map-base /'
49
+ end
50
+
51
+ # Setup extra options
52
+ #
53
+ # @since 0.2.0
54
+ # @api private
55
+ def setup_extra
56
+ return unless Mwc.config.project.options.any?
57
+
58
+ Mwc.config.project.options.each do |name, value|
59
+ @options.push "-s #{name}=#{value}"
60
+ end
61
+ end
62
+
63
+ # Convert options to string
64
+ #
65
+ # @return [String] the options
66
+ def to_s
67
+ @options.join(' ')
68
+ end
69
+
70
+ # Configure extra javacript
71
+ #
72
+ # @since 0.2.0
73
+ # @api private
74
+ %i[library_js pre_js post_js].each do |type|
75
+ define_method "add_#{type}" do |items|
76
+ items.each do |path|
77
+ @options.push "#{EXTRA_JS_TYPE[type]} #{path}"
78
+ end
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ # Configure output format
85
+ #
86
+ # @param foramt [String] output format
87
+ #
88
+ # @since 0.1.0
89
+ # @api private
90
+ def output(format)
91
+ @options.push "-o dist/#{Mwc.config.project.name}.#{format}"
92
+ end
93
+ end
94
+ end
data/lib/mwc/config.rb ADDED
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'singleton'
5
+
6
+ require 'mwc/project'
7
+ require 'mwc/mruby'
8
+ require 'mwc'
9
+
10
+ module Mwc
11
+ # The compile preferences
12
+ class Config
13
+ class << self
14
+ extend Forwardable
15
+
16
+ delegate %i[
17
+ exist?
18
+ mruby
19
+ ] => :instance
20
+ end
21
+
22
+ include Singleton
23
+
24
+ attr_reader :project, :mruby
25
+
26
+ # :nodoc:
27
+ def initialize
28
+ @path = Mwc.root.join('.mwcrc')
29
+ @project = Project.new
30
+ @mruby = MRuby.new
31
+
32
+ load_config if exist?
33
+ end
34
+
35
+ # TODO: Move to DSL module
36
+ # Set name
37
+ #
38
+ # @param name [String|NilClass] the name
39
+ #
40
+ # @since 0.1.0
41
+ # @api private
42
+ def name(name = nil)
43
+ return @name if name.nil?
44
+
45
+ @name = name.to_s
46
+ end
47
+
48
+ # Check config file exists
49
+ #
50
+ # @return [TrueClass,FalseClass] exist or not
51
+ #
52
+ # @since 0.1.0
53
+ # @api private
54
+ def exist?
55
+ @path.exist?
56
+ end
57
+
58
+ # Reload config
59
+ #
60
+ # @since 0.1.0
61
+ # @api private
62
+ def reload!
63
+ # TODO: Update path when root changed
64
+ @path = Mwc.root.join('.mwcrc')
65
+ return unless exist?
66
+
67
+ load_config
68
+ end
69
+
70
+ private
71
+
72
+ # Laod .mwcrc config
73
+ #
74
+ # @since 0.1.0
75
+ # @api private
76
+ def load_config
77
+ # TODO: Improve config DSL
78
+ instance_eval(@path.read)
79
+ end
80
+ end
81
+ end
data/lib/mwc/mruby.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mwc'
4
+
5
+ module Mwc
6
+ # MRuby config
7
+ class MRuby
8
+ attr_accessor :version
9
+
10
+ def path
11
+ Mwc.root.join('vendor/mruby')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mwc
4
+ # The project settings
5
+ class Project
6
+ attr_accessor :name, :shell, :source_map
7
+ attr_reader :options
8
+
9
+ # :nodoc:
10
+ def initialize
11
+ @options = {}
12
+ end
13
+
14
+ # Add customize options
15
+ #
16
+ # @param name [String] the option name
17
+ # @param value [String] the option value
18
+ #
19
+ # @since 0.2.0
20
+ # @api private
21
+ def option(name, value)
22
+ @options[name] = value
23
+ end
24
+ end
25
+ end
data/lib/mwc/server.rb ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require 'forwardable'
5
+ require 'rack'
6
+
7
+ require 'mwc'
8
+
9
+ module Mwc
10
+ # Static assets server
11
+ class Server
12
+ WASM_RULE = /\.(?:wasm)\z/.freeze
13
+ WASM_HEADER = { 'Content-Type' => 'application/wasm' }.freeze
14
+
15
+ def initialize
16
+ @static =
17
+ Rack::Static.new(
18
+ ->(_) { [404, {}, []] },
19
+ root: 'dist', # TODO: Set by config
20
+ index: "#{Mwc.config.project.name}.html",
21
+ urls: [''],
22
+ header_rules: [
23
+ [WASM_RULE, WASM_HEADER]
24
+ ]
25
+ )
26
+ end
27
+
28
+ def call(env)
29
+ @static.call(env)
30
+ end
31
+ end
32
+ end
data/lib/mwc/tasks.rb ADDED
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake/tasklib'
4
+
5
+ require 'mwc/compile_options'
6
+ require 'mwc'
7
+
8
+ module Mwc
9
+ # :nodoc:
10
+ class Tasks < Rake::TaskLib
11
+ SOURCES = FileList['src/**/*.c']
12
+ BINARIES = SOURCES.ext('bc')
13
+ LIBRARY_JS = FileList['src/js/**/*.lib.js']
14
+ PRE_JS = FileList['src/js/**/*.pre.js']
15
+ POST_JS = FileList['src/js/**/*.post.js']
16
+
17
+ # :nodoc:
18
+ def initialize
19
+ return unless mruby_directory.join('Rakefile').exist?
20
+
21
+ namespace :mruby do
22
+ ENV['MRUBY_CONFIG'] = Mwc.root.join('config', 'build.rb').to_s
23
+ # TODO: Prevent load error breaks command
24
+ load mruby_directory.join('Rakefile')
25
+ end
26
+
27
+ compile_binary_task
28
+ compile_wasm_task
29
+ end
30
+
31
+ private
32
+
33
+ # :nodoc:
34
+ def compile_binary_task
35
+ rule '.bc' => SOURCES do |task|
36
+ sh "emcc -I #{mruby_directory.join('include')} -I include -c " \
37
+ "#{task.source} -o #{task.name}"
38
+ end
39
+ end
40
+
41
+ # :nodoc:
42
+ def compile_wasm_task
43
+ %i[wasm html js].each do |format|
44
+ task "mruby.#{format}" => ['mruby:all'].concat(BINARIES) do
45
+ compile(format)
46
+ end
47
+
48
+ desc "Compile sources to #{format} WebAssembly"
49
+ task format => "mruby.#{format}"
50
+ end
51
+ end
52
+
53
+ # :nodoc:
54
+ def compile(format)
55
+ do_compile CompileOptions.new(
56
+ format: format,
57
+ library_js: LIBRARY_JS,
58
+ pre_js: PRE_JS,
59
+ post_js: POST_JS
60
+ )
61
+ end
62
+
63
+ # :nodoc:
64
+ def do_compile(options)
65
+ sh "emcc #{sources.join(' ')} #{options}"
66
+ end
67
+
68
+ # :nodoc:
69
+ def libmruby
70
+ mruby_directory.join('build/wasm/lib/libmruby.bc')
71
+ end
72
+
73
+ # :nodoc:
74
+ def sources
75
+ [libmruby].concat(BINARIES)
76
+ end
77
+
78
+ # :nodoc:
79
+ def mruby_directory
80
+ Mwc.config.mruby.path
81
+ end
82
+ end
83
+ end