glimmer-dsl-swt 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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +47 -0
  4. data/RUBY_VERSION +1 -0
  5. data/VERSION +1 -0
  6. data/bin/girb +10 -0
  7. data/bin/girb_runner.rb +13 -0
  8. data/bin/glimmer +5 -0
  9. data/icons/scaffold_app.icns +0 -0
  10. data/lib/ext/glimmer.rb +13 -0
  11. data/lib/ext/glimmer/config.rb +18 -0
  12. data/lib/glimmer-dsl-swt.rb +12 -0
  13. data/lib/glimmer/data_binding/list_selection_binding.rb +52 -0
  14. data/lib/glimmer/data_binding/model_binding.rb +248 -0
  15. data/lib/glimmer/data_binding/observable.rb +21 -0
  16. data/lib/glimmer/data_binding/observable_array.rb +107 -0
  17. data/lib/glimmer/data_binding/observable_model.rb +108 -0
  18. data/lib/glimmer/data_binding/observable_widget.rb +17 -0
  19. data/lib/glimmer/data_binding/observer.rb +124 -0
  20. data/lib/glimmer/data_binding/shine.rb +23 -0
  21. data/lib/glimmer/data_binding/table_items_binding.rb +56 -0
  22. data/lib/glimmer/data_binding/tree_items_binding.rb +71 -0
  23. data/lib/glimmer/data_binding/widget_binding.rb +33 -0
  24. data/lib/glimmer/dsl/swt/async_exec_expression.rb +14 -0
  25. data/lib/glimmer/dsl/swt/bind_expression.rb +37 -0
  26. data/lib/glimmer/dsl/swt/color_expression.rb +19 -0
  27. data/lib/glimmer/dsl/swt/column_properties_expression.rb +24 -0
  28. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +42 -0
  29. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +39 -0
  30. data/lib/glimmer/dsl/swt/data_binding_expression.rb +34 -0
  31. data/lib/glimmer/dsl/swt/dialog_expression.rb +26 -0
  32. data/lib/glimmer/dsl/swt/display_expression.rb +19 -0
  33. data/lib/glimmer/dsl/swt/dsl.rb +34 -0
  34. data/lib/glimmer/dsl/swt/exec_expression.rb +28 -0
  35. data/lib/glimmer/dsl/swt/layout_data_expression.rb +25 -0
  36. data/lib/glimmer/dsl/swt/layout_expression.rb +27 -0
  37. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +44 -0
  38. data/lib/glimmer/dsl/swt/menu_bar_expression.rb +33 -0
  39. data/lib/glimmer/dsl/swt/menu_expression.rb +32 -0
  40. data/lib/glimmer/dsl/swt/message_box_expression.rb +29 -0
  41. data/lib/glimmer/dsl/swt/observe_expression.rb +32 -0
  42. data/lib/glimmer/dsl/swt/property_expression.rb +22 -0
  43. data/lib/glimmer/dsl/swt/rgb_expression.rb +12 -0
  44. data/lib/glimmer/dsl/swt/rgba_expression.rb +12 -0
  45. data/lib/glimmer/dsl/swt/shell_expression.rb +25 -0
  46. data/lib/glimmer/dsl/swt/swt_expression.rb +25 -0
  47. data/lib/glimmer/dsl/swt/sync_exec_expression.rb +15 -0
  48. data/lib/glimmer/dsl/swt/tab_item_expression.rb +33 -0
  49. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +31 -0
  50. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +31 -0
  51. data/lib/glimmer/dsl/swt/tree_properties_expression.rb +26 -0
  52. data/lib/glimmer/dsl/swt/widget_expression.rb +35 -0
  53. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +32 -0
  54. data/lib/glimmer/launcher.rb +196 -0
  55. data/lib/glimmer/package.rb +57 -0
  56. data/lib/glimmer/rake_task.rb +62 -0
  57. data/lib/glimmer/scaffold.rb +582 -0
  58. data/lib/glimmer/swt/color_proxy.rb +53 -0
  59. data/lib/glimmer/swt/display_proxy.rb +88 -0
  60. data/lib/glimmer/swt/font_proxy.rb +72 -0
  61. data/lib/glimmer/swt/layout_data_proxy.rb +84 -0
  62. data/lib/glimmer/swt/layout_proxy.rb +82 -0
  63. data/lib/glimmer/swt/menu_proxy.rb +101 -0
  64. data/lib/glimmer/swt/message_box_proxy.rb +48 -0
  65. data/lib/glimmer/swt/packages.rb +13 -0
  66. data/lib/glimmer/swt/shell_proxy.rb +152 -0
  67. data/lib/glimmer/swt/swt_proxy.rb +106 -0
  68. data/lib/glimmer/swt/tab_item_proxy.rb +65 -0
  69. data/lib/glimmer/swt/table_proxy.rb +150 -0
  70. data/lib/glimmer/swt/tree_proxy.rb +120 -0
  71. data/lib/glimmer/swt/widget_listener_proxy.rb +34 -0
  72. data/lib/glimmer/swt/widget_proxy.rb +489 -0
  73. data/lib/glimmer/ui/custom_shell.rb +45 -0
  74. data/lib/glimmer/ui/custom_widget.rb +244 -0
  75. data/lib/glimmer/util/proc_tracker.rb +16 -0
  76. data/vendor/swt/linux/swt.jar +0 -0
  77. data/vendor/swt/mac/swt.jar +0 -0
  78. data/vendor/swt/windows/swt.jar +0 -0
  79. metadata +307 -0
@@ -0,0 +1,35 @@
1
+ require 'glimmer'
2
+ require 'glimmer/dsl/expression'
3
+ require 'glimmer/dsl/parent_expression'
4
+
5
+ module Glimmer
6
+ module DSL
7
+ module SWT
8
+ class WidgetExpression < Expression
9
+ include ParentExpression
10
+
11
+ EXCLUDED_KEYWORDS = %w[shell display tab_item]
12
+
13
+ def can_interpret?(parent, keyword, *args, &block)
14
+ !EXCLUDED_KEYWORDS.include?(keyword) and
15
+ parent.respond_to?(:swt_widget) and #TODO change to composite?(parent)
16
+ Glimmer::SWT::WidgetProxy.widget_exists?(keyword)
17
+ end
18
+
19
+ def interpret(parent, keyword, *args, &block)
20
+ begin
21
+ class_name = "#{keyword.camelcase(:upper)}Proxy".to_sym
22
+ widget_class = Glimmer::SWT.const_get(class_name)
23
+ rescue
24
+ widget_class = Glimmer::SWT::WidgetProxy
25
+ end
26
+ widget_class.new(keyword, parent, args)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ require 'glimmer/swt/widget_proxy'
34
+ require 'glimmer/swt/tree_proxy'
35
+ require 'glimmer/swt/table_proxy'
@@ -0,0 +1,32 @@
1
+ require 'glimmer/dsl/expression'
2
+ require 'glimmer/swt/display_proxy'
3
+
4
+ module Glimmer
5
+ module DSL
6
+ module SWT
7
+ class WidgetListenerExpression < Expression
8
+ include_package 'org.eclipse.swt.widgets'
9
+
10
+ def can_interpret?(parent, keyword, *args, &block)
11
+ Glimmer::Config.logger&.debug "keyword starts with on_: #{keyword.start_with?('on_')}"
12
+ return false unless keyword.start_with?('on_')
13
+ widget_or_display_parentage = parent.respond_to?(:swt_widget) || parent.is_a?(Glimmer::SWT::DisplayProxy)
14
+ Glimmer::Config.logger&.debug "parent is a widget or display: #{widget_or_display_parentage}"
15
+ return false unless widget_or_display_parentage
16
+ Glimmer::Config.logger&.debug "block exists?: #{!block.nil?}"
17
+ raise Glimmer::Error, "Listener is missing block for keyword: #{keyword}" unless block_given?
18
+ Glimmer::Config.logger&.debug "args are empty?: #{args.empty?}"
19
+ raise Glimmer::Error, "Invalid listener arguments for keyword: #{keyword}(#{args})" unless args.empty?
20
+ result = parent.can_handle_observation_request?(keyword)
21
+ Glimmer::Config.logger&.debug "can add listener? #{result}"
22
+ raise Glimmer::Error, "Invalid listener keyword: #{keyword}" unless result
23
+ true
24
+ end
25
+
26
+ def interpret(parent, keyword, *args, &block)
27
+ parent.handle_observation_request(keyword, &block)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,196 @@
1
+ require_relative 'rake_task'
2
+
3
+ module Glimmer
4
+ class Launcher
5
+ OPERATING_SYSTEMS_SUPPORTED = ["mac", "windows", "linux"]
6
+
7
+ TEXT_USAGE_PREFIX = <<~MULTI_LINE_STRING
8
+ Usage: glimmer [--quiet] [--debug] [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-jruby-option]...] (application.rb or task[task_args]) [[application2.rb]...]
9
+
10
+ Runs Glimmer applications/tasks.
11
+
12
+ Either a single task or one or more applications may be specified.
13
+
14
+ When a task is specified, it runs via rake. Some tasks take arguments in square brackets.
15
+
16
+ Available tasks are below (you may also lookup by adding `require 'glimmer/rake_task'` in Rakefile and running rake -T):
17
+ MULTI_LINE_STRING
18
+
19
+ TEXT_USAGE_SUFFIX = <<~MULTI_LINE_STRING
20
+
21
+ When applications are specified, they are run using JRuby,
22
+ automatically preloading the glimmer Ruby gem and SWT jar dependency.
23
+
24
+ Optionally, extra Glimmer options, JRuby options and environment variables may be passed in.
25
+
26
+ Glimmer options:
27
+ - "--quiet" : Does not announce file path of Glimmer application being launched
28
+ - "--debug" : Displays extra debugging information, passes "--debug" to JRuby, and enables debug logging
29
+ - "--log-level=VALUE" : Sets Glimmer's Ruby logger level ("ERROR" / "WARN" / "INFO" / "DEBUG"; default is none)
30
+
31
+ Example: glimmer samples/hello_world.rb
32
+
33
+ This runs the Glimmer application samples/hello_world.rb
34
+ MULTI_LINE_STRING
35
+
36
+ GLIMMER_LIB_LOCAL = File.expand_path(File.join(__FILE__, '..', '..', 'glimmer-dsl-swt.rb'))
37
+ GLIMMER_LIB_GEM = 'glimmer-dsl-swt'
38
+ GLIMMER_OPTIONS = %w[--log-level --quiet]
39
+ GLIMMER_OPTION_ENV_VAR_MAPPING = {
40
+ '--log-level' => 'GLIMMER_LOGGER_LEVEL'
41
+ }
42
+ REGEX_RAKE_TASK_WITH_ARGS = /^([^\[]+)\[?([^\]]*)\]?$/
43
+
44
+ @@mutex = Mutex.new
45
+
46
+ class << self
47
+ def platform_os
48
+ OPERATING_SYSTEMS_SUPPORTED.detect {|os| OS.send("#{os}?")}
49
+ end
50
+
51
+ def swt_jar_file
52
+ @swt_jar_file ||= File.expand_path(File.join(__FILE__, '..', '..', '..', 'vendor', 'swt', platform_os, 'swt.jar'))
53
+ end
54
+
55
+ def jruby_os_specific_options
56
+ OS.mac? ? "-J-XstartOnFirstThread" : ""
57
+ end
58
+
59
+ def jruby_swt_options
60
+ "#{jruby_os_specific_options} -J-classpath \"#{swt_jar_file}\""
61
+ end
62
+
63
+ def glimmer_lib
64
+ @@mutex.synchronize do
65
+ unless @glimmer_lib
66
+ @glimmer_lib = GLIMMER_LIB_GEM
67
+ glimmer_gem_listing = `jgem list #{GLIMMER_LIB_GEM}`.split("\n").map {|l| l.split.first}
68
+ if !glimmer_gem_listing.include?(GLIMMER_LIB_GEM) && File.exists?(GLIMMER_LIB_LOCAL)
69
+ @glimmer_lib = GLIMMER_LIB_LOCAL
70
+ puts "[DEVELOPMENT MODE] (detected #{@glimmer_lib})"
71
+ end
72
+ end
73
+ end
74
+ @glimmer_lib
75
+ end
76
+
77
+ def glimmer_option_env_vars(glimmer_options)
78
+ GLIMMER_OPTION_ENV_VAR_MAPPING.reduce({}) do |hash, pair|
79
+ glimmer_options[pair.first] ? hash.merge(GLIMMER_OPTION_ENV_VAR_MAPPING[pair.first] => glimmer_options[pair.first]) : hash
80
+ end
81
+ end
82
+
83
+ def load_env_vars(env_vars)
84
+ env_vars.each do |key, value|
85
+ ENV[key] = value
86
+ end
87
+ end
88
+
89
+ def launch(application, jruby_options: [], env_vars: {}, glimmer_options: {})
90
+ jruby_options_string = jruby_options.join(' ') + ' ' if jruby_options.any?
91
+ env_vars = env_vars.merge(glimmer_option_env_vars(glimmer_options))
92
+ env_vars_string = env_vars.map {|k,v| "#{k}=#{v}"}.join(' ')
93
+ the_glimmer_lib = glimmer_lib
94
+ devmode_require = nil
95
+ if the_glimmer_lib == GLIMMER_LIB_LOCAL
96
+ devmode_require = '-r puts_debuggerer '
97
+ end
98
+ rake_tasks = Rake.application.tasks.map(&:to_s).map {|t| t.sub('glimmer:', '')}
99
+ potential_rake_task_parts = application.match(REGEX_RAKE_TASK_WITH_ARGS)
100
+ application = potential_rake_task_parts[1]
101
+ rake_task_args = potential_rake_task_parts[2].split(',')
102
+ if rake_tasks.include?(application)
103
+ load_env_vars(glimmer_option_env_vars(glimmer_options))
104
+ rake_task = "glimmer:#{application}"
105
+ puts "Running Glimmer rake task: #{rake_task}" if jruby_options_string.to_s.include?('--debug')
106
+ Rake::Task[rake_task].invoke(*rake_task_args)
107
+ else
108
+ @@mutex.synchronize do
109
+ puts "Launching Glimmer Application: #{application}" if jruby_options_string.to_s.include?('--debug') || glimmer_options['--quiet'].to_s.downcase != 'true'
110
+ end
111
+ command = "#{env_vars_string} jruby #{jruby_options_string}#{jruby_os_specific_options} #{devmode_require}-r #{the_glimmer_lib} -S #{application}"
112
+ puts command if jruby_options_string.to_s.include?('--debug')
113
+ system command
114
+ end
115
+ end
116
+ end
117
+
118
+ attr_reader :application_paths
119
+ attr_reader :env_vars
120
+ attr_reader :glimmer_options
121
+ attr_reader :jruby_options
122
+
123
+ def initialize(raw_options)
124
+ raw_options << '--quiet' if !caller.join("\n").include?('/bin/glimmer:') && !raw_options.join.include?('--quiet=')
125
+ raw_options << '--log-level=DEBUG' if raw_options.join.include?('--debug') && !raw_options.join.include?('--log-level=')
126
+ @application_paths = extract_application_paths(raw_options)
127
+ @env_vars = extract_env_vars(raw_options)
128
+ @glimmer_options = extract_glimmer_options(raw_options)
129
+ @jruby_options = raw_options
130
+ end
131
+
132
+ def launch
133
+ if @application_paths.empty?
134
+ display_usage
135
+ else
136
+ launch_application
137
+ end
138
+ end
139
+
140
+ private
141
+
142
+ def launch_application
143
+ load File.expand_path('./Rakefile') if File.exist?(File.expand_path('./Rakefile')) && caller.join("\n").include?('/bin/glimmer:')
144
+ threads = @application_paths.map do |application_path|
145
+ Thread.new do
146
+ self.class.launch(
147
+ application_path,
148
+ jruby_options: @jruby_options,
149
+ env_vars: @env_vars,
150
+ glimmer_options: @glimmer_options
151
+ )
152
+ end
153
+ end
154
+ threads.each(&:join)
155
+ end
156
+
157
+ def display_usage
158
+ rake_tasks = `rake -T`.gsub('rake glimmer:', 'glimmer ').split("\n").select {|l| l.start_with?('glimmer ')}
159
+ puts TEXT_USAGE_PREFIX
160
+ puts rake_tasks.join("\n")
161
+ puts TEXT_USAGE_SUFFIX
162
+ end
163
+
164
+ def extract_application_paths(options)
165
+ options.select do |option|
166
+ !option.start_with?('-') && !option.include?('=')
167
+ end.each do |application_path|
168
+ options.delete(application_path)
169
+ end
170
+ end
171
+
172
+ def extract_env_vars(options)
173
+ options.select do |option|
174
+ !option.start_with?('-') && option.include?('=')
175
+ end.each do |env_var|
176
+ options.delete(env_var)
177
+ end.reduce({}) do |hash, env_var_string|
178
+ match = env_var_string.match(/^([^=]+)=(.+)$/)
179
+ hash.merge(match[1] => match[2])
180
+ end
181
+ end
182
+
183
+ def extract_glimmer_options(options)
184
+ options.select do |option|
185
+ GLIMMER_OPTIONS.reduce(false) do |result, glimmer_option|
186
+ result || option.include?(glimmer_option)
187
+ end
188
+ end.each do |glimmer_option|
189
+ options.delete(glimmer_option)
190
+ end.reduce({}) do |hash, glimmer_option_string|
191
+ match = glimmer_option_string.match(/^([^=]+)=?(.+)?$/)
192
+ hash.merge(match[1] => (match[2] || 'true'))
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,57 @@
1
+ require 'os'
2
+
3
+ module Glimmer
4
+ module Package
5
+ class << self
6
+ attr_accessor :javapackager_extra_args
7
+
8
+ def config
9
+ project_name = File.basename(File.expand_path('.'))
10
+ if !File.exists?('config/warble.rb')
11
+ puts 'Generating JAR configuration (config/warble.rb) to use with Warbler...'
12
+ system('mkdir -p config')
13
+ system('warble config')
14
+ new_config = File.read('config/warble.rb').split("\n").inject('') do |output, line|
15
+ if line.include?('config.dirs =')
16
+ line = line.sub('# ', '').sub(/=[^=\n]+$/, '= %w(app config db lib script bin docs fonts icons images sounds videos)')
17
+ end
18
+ if line.include?('config.includes =')
19
+ line = line.sub('# ', '').sub(/=[^=\n]+$/, "= FileList['LICENSE.txt', 'VERSION']")
20
+ end
21
+ if line.include?('config.autodeploy_dir =')
22
+ line = line.sub('# ', '')
23
+ end
24
+ output + "\n" + line
25
+ end
26
+ File.write('config/warble.rb', new_config)
27
+ end
28
+ end
29
+
30
+ def jar
31
+ system('mkdir -p dist')
32
+ puts "Generating JAR with Warbler..."
33
+ system('warble')
34
+ end
35
+
36
+ def native
37
+ require 'facets/string/titlecase'
38
+ require 'facets/string/underscore'
39
+ project_name = File.basename(File.expand_path('.'))
40
+ version_file = File.expand_path('./VERSION')
41
+ version = (File.read(version_file).strip if File.exists?(version_file) && File.file?(version_file)) rescue nil
42
+ license_file = File.expand_path('./LICENSE.txt')
43
+ license = (File.read(license_file).strip if File.exists?(license_file) && File.file?(license_file)) rescue nil
44
+ human_name = project_name.underscore.titlecase
45
+ command = "javapackager -deploy -native -outdir packages -outfile \"#{project_name}\" -srcfiles \"dist/#{project_name}.jar\" -appclass JarMain -name \"#{human_name}\" -title \"#{human_name}\" -Bmac.CFBundleName=\"#{human_name}\" -Bmac.CFBundleIdentifier=\"org.#{project_name}.application.#{project_name}\" -Bmac.category=\"public.app-category.business\" "
46
+ command += " -BjvmOptions=-XstartOnFirstThread " if OS.mac?
47
+ command += " -BappVersion=#{version} -Bmac.CFBundleVersion=#{version} " if version
48
+ command += " -srcfiles LICENSE.txt -BlicenseFile=LICENSE.txt " if license
49
+ command += " #{javapackager_extra_args} " if javapackager_extra_args
50
+ command += " #{ENV['JAVAPACKAGER_EXTRA_ARGS']} " if ENV['JAVAPACKAGER_EXTRA_ARGS']
51
+ puts "Generating DMG/PKG/APP/JNLP with javapackager..."
52
+ puts command
53
+ system command
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,62 @@
1
+ require 'rake'
2
+
3
+ require_relative 'package'
4
+
5
+ namespace :glimmer do
6
+ namespace :package do
7
+ desc 'Generate JAR config file'
8
+ task :config do
9
+ Glimmer::Package.config
10
+ end
11
+
12
+ desc 'Generate JAR file'
13
+ task :jar do
14
+ Glimmer::Package.jar
15
+ end
16
+
17
+ desc 'Generate Native files (DMG/PKG/APP on the Mac, EXE on Windows, RPM/DEB on Linux)'
18
+ task :native do
19
+ Glimmer::Package.native
20
+ end
21
+ end
22
+
23
+ desc 'Package app for distribution (generating config, jar, and native files)'
24
+ task :package do
25
+ Rake::Task['glimmer:package:config'].execute
26
+ Rake::Task['glimmer:package:jar'].execute
27
+ Rake::Task['glimmer:package:native'].execute
28
+ end
29
+
30
+
31
+ desc 'Scaffold a Glimmer application directory structure to begin building a new app'
32
+ task :scaffold, [:app_name] do |t, args|
33
+ require_relative 'scaffold'
34
+ Scaffold.app(args[:app_name])
35
+ end
36
+
37
+ namespace :scaffold do
38
+ desc 'Scaffold a Glimmer::UI::CustomShell subclass (represents a full window view) under app/views (namespace is optional)'
39
+ task :custom_shell, [:custom_shell_name, :namespace] do |t, args|
40
+ require_relative 'scaffold'
41
+ Scaffold.custom_shell(args[:custom_shell_name], args[:namespace])
42
+ end
43
+
44
+ desc 'Scaffold a Glimmer::UI::CustomWidget subclass (represents a part of a view) under app/views (namespace is optional)'
45
+ task :custom_widget, [:custom_widget_name, :namespace] do |t, args|
46
+ require_relative 'scaffold'
47
+ Scaffold.custom_widget(args[:custom_widget_name], args[:namespace])
48
+ end
49
+
50
+ desc 'Scaffold a Glimmer::UI::CustomShell subclass (represents a full window view) under its own Ruby gem + app project (namespace is required)'
51
+ task :custom_shell_gem, [:custom_shell_name, :namespace] do |t, args|
52
+ require_relative 'scaffold'
53
+ Scaffold.custom_shell_gem(args[:custom_shell_name], args[:namespace])
54
+ end
55
+
56
+ desc 'Scaffold a Glimmer::UI::CustomWidget subclass (represents a part of a view) under its own Ruby gem project (namespace is required)'
57
+ task :custom_widget_gem, [:custom_widget_name, :namespace] do |t, args|
58
+ require_relative 'scaffold'
59
+ Scaffold.custom_widget_gem(args[:custom_widget_name], args[:namespace])
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,582 @@
1
+ require 'fileutils'
2
+ require 'os'
3
+ require 'facets'
4
+
5
+ class Scaffold
6
+ class << self
7
+ include FileUtils
8
+
9
+ VERSION = File.read(File.expand_path('../../../VERSION', __FILE__)).strip
10
+ RUBY_VERSION = File.read(File.expand_path('../../../RUBY_VERSION', __FILE__)).strip
11
+
12
+ # TODO externalize all constants into scaffold/files
13
+
14
+ GITIGNORE = <<~MULTI_LINE_STRING
15
+ *.gem
16
+ *.rbc
17
+ /.config
18
+ /coverage/
19
+ /InstalledFiles
20
+ /pkg/
21
+ /spec/reports/
22
+ /spec/examples.txt
23
+ /test/tmp/
24
+ /test/version_tmp/
25
+ /tmp/
26
+
27
+ # Used by dotenv library to load environment variables.
28
+ # .env
29
+
30
+ ## Specific to RubyMotion:
31
+ .dat*
32
+ .repl_history
33
+ build/
34
+ *.bridgesupport
35
+ build-iPhoneOS/
36
+ build-iPhoneSimulator/
37
+
38
+ ## Specific to RubyMotion (use of CocoaPods):
39
+ #
40
+ # We recommend against adding the Pods directory to your .gitignore. However
41
+ # you should judge for yourself, the pros and cons are mentioned at:
42
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
43
+ #
44
+ # vendor/Pods/
45
+
46
+ ## Documentation cache and generated files:
47
+ /.yardoc/
48
+ /_yardoc/
49
+ /doc/
50
+ /rdoc/
51
+
52
+ ## Environment normalization:
53
+ /.bundle/
54
+ /vendor/bundle
55
+ /lib/bundler/man/
56
+
57
+ # for a library or gem, you might want to ignore these files since the code is
58
+ # intended to run in multiple environments; otherwise, check them in:
59
+ Gemfile.lock
60
+ # .ruby-version
61
+ # .ruby-gemset
62
+
63
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
64
+ .rvmrc
65
+
66
+ # Mac
67
+ .DS_Store
68
+
69
+ # Gladiator (Glimmer Editor)
70
+ .gladiator
71
+
72
+ # Glimmer
73
+ dist
74
+ packages
75
+ MULTI_LINE_STRING
76
+
77
+ GEMFILE_APP = <<~MULTI_LINE_STRING
78
+ # frozen_string_literal: true
79
+
80
+ source 'https://rubygems.org'
81
+
82
+ git_source(:github) {|repo_name| "https://github.com/\#{repo_name}" }
83
+
84
+ gem 'glimmer-dsl-swt', '~> #{VERSION}'
85
+
86
+ group :test do
87
+ gem 'rspec'
88
+ end
89
+ MULTI_LINE_STRING
90
+
91
+ GEMFILE_GEM = <<~MULTI_LINE_STRING
92
+ # frozen_string_literal: true
93
+
94
+ source 'https://rubygems.org'
95
+
96
+ git_source(:github) {|repo_name| "https://github.com/\#{repo_name}" }
97
+
98
+ gem 'glimmer-dsl-swt', '~> #{VERSION}'
99
+
100
+ group :development do
101
+ gem 'rspec', '~> 3.5.0'
102
+ gem 'jeweler', '2.3.9'
103
+ gem 'simplecov', '>= 0'
104
+ end
105
+ MULTI_LINE_STRING
106
+
107
+ RAKEFILE = <<~MULTI_LINE_STRING
108
+ require 'glimmer/rake_task'
109
+
110
+ ## Use the following configuration if you would like to customize javapackager
111
+ ## arguments for `glimmer package` command.
112
+ #
113
+ # Glimmer::Package.javapackager_extra_args =
114
+ # " -BlicenseType=" +
115
+ # " -Bmac.CFBundleIdentifier=" +
116
+ # " -Bmac.category=" +
117
+ # " -Bmac.signing-key-developer-id-app="
118
+ MULTI_LINE_STRING
119
+
120
+ RVM_FUNCTION = <<~MULTI_LINE_STRING
121
+ # Load RVM into a shell session *as a function*
122
+ if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
123
+
124
+ # First try to load from a user install
125
+ source "$HOME/.rvm/scripts/rvm"
126
+
127
+ elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
128
+
129
+ # Then try to load from a root install
130
+ source "/usr/local/rvm/scripts/rvm"
131
+
132
+ fi
133
+ MULTI_LINE_STRING
134
+
135
+ def app(app_name)
136
+ mkdir app_name
137
+ cd app_name
138
+ write '.gitignore', GITIGNORE
139
+ write '.ruby-version', RUBY_VERSION
140
+ write '.ruby-gemset', app_name
141
+ write 'VERSION', '1.0.0'
142
+ write 'LICENSE.txt', "Copyright (c) #{Time.now.year} #{app_name}"
143
+ write 'Gemfile', GEMFILE_APP
144
+ write 'Rakefile', RAKEFILE
145
+ mkdir 'app'
146
+ write "app/#{file_name(app_name)}.rb", app_main_file(app_name)
147
+ mkdir 'app/models'
148
+ mkdir 'app/views'
149
+ custom_shell('AppView', current_dir_name, :app)
150
+ if OS.mac?
151
+ mkdir_p 'package/macosx'
152
+ icon_file = "package/macosx/#{human_name(app_name)}.icns"
153
+ cp File.expand_path('../../../icons/scaffold_app.icns', __FILE__), icon_file
154
+ puts "Created #{current_dir_name}/#{icon_file}"
155
+ end
156
+ mkdir 'bin'
157
+ write "bin/#{file_name(app_name)}", app_bin_file(app_name)
158
+ FileUtils.chmod 0755, "bin/#{file_name(app_name)}"
159
+ system "bash -c '#{RVM_FUNCTION}\n cd .\n bundle\n glimmer package\n'"
160
+ system "open packages/bundles/#{human_name(app_name).gsub(' ', '\ ')}.app"
161
+ # TODO generate rspec test suite
162
+ end
163
+
164
+ def custom_shell(custom_shell_name, namespace, shell_type = nil)
165
+ namespace ||= current_dir_name
166
+ root_dir = File.exists?('app') ? 'app' : 'lib'
167
+ parent_dir = "#{root_dir}/views/#{file_name(namespace)}"
168
+ mkdir_p parent_dir unless File.exists?(parent_dir)
169
+ write "#{parent_dir}/#{file_name(custom_shell_name)}.rb", custom_shell_file(custom_shell_name, namespace, shell_type)
170
+ end
171
+
172
+ def custom_widget(custom_widget_name, namespace)
173
+ namespace ||= current_dir_name
174
+ root_dir = File.exists?('app') ? 'app' : 'lib'
175
+ parent_dir = "#{root_dir}/views/#{file_name(namespace)}"
176
+ mkdir_p parent_dir unless File.exists?(parent_dir)
177
+ write "#{parent_dir}/#{file_name(custom_widget_name)}.rb", custom_widget_file(custom_widget_name, namespace)
178
+ end
179
+
180
+ def custom_shell_gem(custom_shell_name, namespace)
181
+ gem_name = "glimmer-cs-#{compact_name(custom_shell_name)}"
182
+ gem_summary = "#{human_name(custom_shell_name)} - Glimmer Custom Shell"
183
+ if namespace
184
+ gem_name += "-#{compact_name(namespace)}"
185
+ gem_summary += " (#{human_name(namespace)})"
186
+ else
187
+ namespace = 'glimmer'
188
+ end
189
+ system "jeweler --rspec --summary '#{gem_summary}' --description '#{gem_summary}' #{gem_name}"
190
+ cd gem_name
191
+ write '.gitignore', GITIGNORE
192
+ write '.ruby-version', RUBY_VERSION
193
+ write '.ruby-gemset', gem_name
194
+ write 'VERSION', '1.0.0'
195
+ write 'Gemfile', GEMFILE_GEM
196
+ write 'Rakefile', gem_rakefile(custom_shell_name, namespace)
197
+ append "lib/#{gem_name}.rb", gem_main_file(custom_shell_name, namespace)
198
+ mkdir 'lib/views'
199
+ custom_shell(custom_shell_name, namespace, :gem)
200
+ mkdir 'bin'
201
+ write "bin/#{gem_name}", gem_bin_file(gem_name, custom_shell_name, namespace)
202
+ write "bin/#{file_name(custom_shell_name)}", gem_bin_command_file(gem_name)
203
+ FileUtils.chmod 0755, "bin/#{file_name(custom_shell_name)}"
204
+ if OS.mac?
205
+ mkdir_p 'package/macosx'
206
+ icon_file = "package/macosx/#{human_name(custom_shell_name)}.icns"
207
+ cp File.expand_path('../../../icons/scaffold_app.icns', __FILE__), icon_file
208
+ puts "Created #{current_dir_name}/#{icon_file}"
209
+ end
210
+ system "bash -c '#{RVM_FUNCTION}\n cd .\n bundle\n glimmer package\n'"
211
+ system "open packages/bundles/#{human_name(custom_shell_name).gsub(' ', '\ ')}.app"
212
+ puts "Finished creating #{gem_name} Ruby gem."
213
+ puts 'Edit Rakefile to configure gem details.'
214
+ puts 'Run `rake` to execute specs.'
215
+ puts 'Run `rake build` to build gem.'
216
+ puts 'Run `rake release` to release into rubygems.org once ready.'
217
+ end
218
+
219
+ def custom_widget_gem(custom_widget_name, namespace)
220
+ gem_name = "glimmer-cw-#{compact_name(custom_widget_name)}"
221
+ gem_summary = "#{human_name(custom_widget_name)} - Glimmer Custom Widget"
222
+ if namespace
223
+ gem_name += "-#{compact_name(namespace)}"
224
+ gem_summary += " (#{human_name(namespace)})"
225
+ else
226
+ namespace = 'glimmer'
227
+ end
228
+ system "jeweler --rspec --summary '#{gem_summary}' --description '#{gem_summary}' #{gem_name}"
229
+ cd gem_name
230
+ write '.gitignore', GITIGNORE
231
+ write '.ruby-version', RUBY_VERSION
232
+ write '.ruby-gemset', gem_name
233
+ write 'VERSION', '1.0.0'
234
+ write 'Gemfile', GEMFILE_GEM
235
+ write 'Rakefile', gem_rakefile
236
+ write 'spec/spec_helper.rb', spec_helper_file
237
+ append "lib/#{gem_name}.rb", gem_main_file(custom_widget_name, namespace)
238
+ mkdir 'lib/views'
239
+ custom_widget(custom_widget_name, namespace)
240
+ system "bash -c '#{RVM_FUNCTION}\n cd .\n bundle\n'"
241
+ puts "Finished creating #{gem_name} Ruby gem."
242
+ puts 'Edit Rakefile to configure gem details.'
243
+ puts 'Run `rake` to execute specs.'
244
+ puts 'Run `rake build` to build gem.'
245
+ puts 'Run `rake release` to release into rubygems.org once ready.'
246
+ end
247
+
248
+ private
249
+
250
+ def write(file, content)
251
+ File.write file, content
252
+ file_path = File.expand_path(file)
253
+ puts "Created #{current_dir_name}/#{file}"
254
+ end
255
+
256
+ def append(file, content)
257
+ File.open(file, 'a') do |f|
258
+ f.write(content)
259
+ end
260
+ end
261
+
262
+ def current_dir_name
263
+ File.basename(File.expand_path('.'))
264
+ end
265
+
266
+ def class_name(app_name)
267
+ app_name.underscore.camelcase(:upper)
268
+ end
269
+
270
+ def file_name(app_name)
271
+ app_name.underscore
272
+ end
273
+ alias dsl_widget_name file_name
274
+
275
+ def human_name(app_name)
276
+ app_name.underscore.titlecase
277
+ end
278
+
279
+ def compact_name(gem_name)
280
+ gem_name.underscore.camelcase.downcase
281
+ end
282
+
283
+ def app_main_file(app_name)
284
+ <<~MULTI_LINE_STRING
285
+ $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
286
+
287
+ require 'bundler/setup'
288
+ Bundler.require(:default)
289
+ require 'views/#{file_name(app_name)}/app_view'
290
+
291
+ class #{class_name(app_name)}
292
+ include Glimmer
293
+
294
+ APP_ROOT = File.expand_path('../..', __FILE__)
295
+ VERSION = File.read(File.join(APP_ROOT, 'VERSION'))
296
+ LICENSE = File.read(File.join(APP_ROOT, 'LICENSE.txt'))
297
+
298
+ def open
299
+ app_view.open
300
+ end
301
+ end
302
+ MULTI_LINE_STRING
303
+ end
304
+
305
+ def gem_main_file(custom_widget_name, namespace = nil)
306
+ custom_widget_file_path = "views"
307
+ custom_widget_file_path += "/#{file_name(namespace)}" if namespace
308
+ custom_widget_file_path += "/#{file_name(custom_widget_name)}"
309
+
310
+ <<~MULTI_LINE_STRING
311
+ $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
312
+
313
+ require 'glimmer-dsl-swt'
314
+ require '#{custom_widget_file_path}'
315
+ MULTI_LINE_STRING
316
+ end
317
+
318
+ def app_bin_file(app_name)
319
+ <<~MULTI_LINE_STRING
320
+ #!/usr/bin/env ruby
321
+
322
+ require_relative '../app/#{file_name(app_name)}'
323
+
324
+ #{class_name(app_name)}.new.open
325
+ MULTI_LINE_STRING
326
+ end
327
+
328
+ def gem_bin_file(gem_name, custom_shell_name, namespace)
329
+ <<~MULTI_LINE_STRING
330
+ #!/usr/bin/env ruby
331
+
332
+ require_relative '../lib/#{gem_name}'
333
+
334
+ include Glimmer
335
+
336
+ #{dsl_widget_name(custom_shell_name)}.open
337
+ MULTI_LINE_STRING
338
+ end
339
+
340
+ def gem_bin_command_file(gem_name)
341
+ <<~MULTI_LINE_STRING
342
+ #!/usr/bin/env ruby
343
+
344
+ require 'glimmer/launcher'
345
+
346
+ runner = File.expand_path("../#{gem_name}", __FILE__)
347
+ launcher = Glimmer::Launcher.new([runner] + ARGV)
348
+ launcher.launch
349
+ MULTI_LINE_STRING
350
+ end
351
+
352
+ def gem_rakefile(custom_shell_name = nil, namespace = nil)
353
+ rakefile_content = File.read('Rakefile')
354
+ lines = rakefile_content.split("\n")
355
+ require_rake_line_index = lines.index(lines.detect {|l| l.include?("require 'rake'") })
356
+ lines.insert(require_rake_line_index, "require 'glimmer/launcher'")
357
+ gem_files_line_index = lines.index(lines.detect {|l| l.include?('# dependencies defined in Gemfile') })
358
+ if custom_shell_name
359
+ lines.insert(gem_files_line_index, " gem.files = Dir['VERSION', 'LICENSE.txt', 'lib/**/*.rb', 'bin/**/*']")
360
+ lines.insert(gem_files_line_index+1, " gem.executables = ['#{file_name(custom_shell_name)}']")
361
+ else
362
+ lines.insert(gem_files_line_index, " gem.files = Dir['lib/**/*.rb']")
363
+ end
364
+ spec_pattern_line_index = lines.index(lines.detect {|l| l.include?('spec.pattern =') })
365
+ lines.insert(spec_pattern_line_index+1, " spec.ruby_opts = [Glimmer::Launcher.jruby_swt_options]")
366
+ lines << "\nrequire 'glimmer/rake_task'\n"
367
+ file_content = lines.join("\n")
368
+ if custom_shell_name
369
+ file_content << <<~MULTI_LINE_STRING
370
+ Glimmer::Package.javapackager_extra_args =
371
+ " -name '#{human_name(custom_shell_name)}'" +
372
+ " -title '#{human_name(custom_shell_name)}'" +
373
+ " -Bmac.CFBundleName='#{human_name(custom_shell_name)}'" +
374
+ " -Bmac.CFBundleIdentifier='org.#{namespace ? compact_name(namespace) : compact_name(custom_shell_name)}.application.#{compact_name(custom_shell_name)}'"
375
+ # " -BlicenseType=" +
376
+ # " -Bmac.category=" +
377
+ # " -Bmac.signing-key-developer-id-app="
378
+ MULTI_LINE_STRING
379
+ end
380
+ file_content
381
+ end
382
+
383
+ def spec_helper_file
384
+ content = File.read('spec/spec_helper.rb')
385
+ lines = content.split("\n")
386
+ require_line_index = lines.index(lines.detect {|l| l.include?(current_dir_name) })
387
+ lines[require_line_index...require_line_index] = [
388
+ "require 'bundler/setup'",
389
+ 'Bundler.require(:default, :development)',
390
+ ]
391
+ configure_block_line_index = lines.index(lines.detect {|l| l.include?('RSpec.configure do') }) + 1
392
+ lines[configure_block_line_index...configure_block_line_index] = [
393
+ ' # The following ensures rspec tests that instantiate and set Glimmer DSL widgets in @target get cleaned after',
394
+ ' config.after do',
395
+ ' @target.dispose if @target && @target.respond_to?(:dispose)',
396
+ ' Glimmer::DSL::Engine.reset',
397
+ ' end',
398
+ ]
399
+
400
+ lines << "\nrequire 'glimmer/rake_task'\n"
401
+ lines.join("\n")
402
+ end
403
+
404
+ def custom_shell_file(custom_shell_name, namespace, shell_type)
405
+ namespace_type = class_name(namespace) == class_name(current_dir_name) ? 'class' : 'module'
406
+
407
+ custom_shell_file_content = <<-MULTI_LINE_STRING
408
+ #{namespace_type} #{class_name(namespace)}
409
+ class #{class_name(custom_shell_name)}
410
+ include Glimmer::UI::CustomShell
411
+
412
+ MULTI_LINE_STRING
413
+
414
+ if shell_type == :gem
415
+ custom_shell_file_content += <<-MULTI_LINE_STRING
416
+ GEM_ROOT = File.expand_path('../../../..', __FILE__)
417
+ VERSION = File.read(File.join(GEM_ROOT, 'VERSION'))
418
+ LICENSE = File.read(File.join(GEM_ROOT, 'LICENSE.txt'))
419
+
420
+ MULTI_LINE_STRING
421
+ end
422
+
423
+ custom_shell_file_content += <<-MULTI_LINE_STRING
424
+ ## Add options like the following to configure CustomShell by outside consumers
425
+ #
426
+ # options :title, :background_color
427
+ # option :width, default: 320
428
+ # option :height, default: 240
429
+ option :greeting, default: 'Hello, World!'
430
+
431
+ ## Use before_body block to pre-initialize variables to use in body
432
+ #
433
+ #
434
+ MULTI_LINE_STRING
435
+
436
+ if %i[gem app].include?(shell_type)
437
+ custom_shell_file_content += <<-MULTI_LINE_STRING
438
+ before_body {
439
+ Display.setAppName('#{shell_type == :gem ? human_name(custom_shell_name) : human_name(namespace)}')
440
+ Display.setAppVersion(VERSION)
441
+ @display = display {
442
+ on_about {
443
+ display_about_dialog
444
+ }
445
+ on_preferences {
446
+ display_preferences_dialog
447
+ }
448
+ }
449
+ }
450
+ MULTI_LINE_STRING
451
+ else
452
+ custom_shell_file_content += <<-MULTI_LINE_STRING
453
+ # before_body {
454
+ #
455
+ # }
456
+ MULTI_LINE_STRING
457
+ end
458
+
459
+ custom_shell_file_content += <<-MULTI_LINE_STRING
460
+
461
+ ## Use after_body block to setup observers for widgets in body
462
+ #
463
+ # after_body {
464
+ #
465
+ # }
466
+
467
+ ## Add widget content inside custom shell body
468
+ ## Top-most widget must be a shell or another custom shell
469
+ #
470
+ body {
471
+ shell {
472
+ # Replace example content below with custom shell content
473
+ minimum_size 320, 240
474
+ text "#{human_name(namespace)} - #{human_name(custom_shell_name)}"
475
+ grid_layout
476
+ label(:center) {
477
+ text bind(self, :greeting)
478
+ font height: 40
479
+ layout_data :fill, :center, true, true
480
+ }
481
+ }
482
+ }
483
+ MULTI_LINE_STRING
484
+
485
+ if %i[gem app].include?(shell_type)
486
+ custom_shell_file_content += <<-MULTI_LINE_STRING
487
+
488
+ def display_about_dialog
489
+ message_box = MessageBox.new(swt_widget)
490
+ message_box.setText("About")
491
+ message = "#{human_name(namespace)} - #{human_name(custom_shell_name)} \#{VERSION}\n\n"
492
+ message += LICENSE
493
+ message_box.setMessage(message)
494
+ message_box.open
495
+ end
496
+
497
+ def display_preferences_dialog
498
+ dialog(swt_widget) {
499
+ text 'Preferences'
500
+ grid_layout {
501
+ margin_height 5
502
+ margin_width 5
503
+ }
504
+ group {
505
+ row_layout {
506
+ type :vertical
507
+ spacing 10
508
+ }
509
+ text 'Greeting'
510
+ font style: :bold
511
+ [
512
+ 'Hello, World!',
513
+ 'Howdy, Partner!'
514
+ ].each do |greeting_text|
515
+ button(:radio) {
516
+ text greeting_text
517
+ selection bind(self, :greeting) { |g| g == greeting_text }
518
+ layout_data {
519
+ width 160
520
+ }
521
+ on_widget_selected { |event|
522
+ self.greeting = event.widget.getText
523
+ }
524
+ }
525
+ end
526
+ }
527
+ }.open
528
+ end
529
+ MULTI_LINE_STRING
530
+ end
531
+
532
+ custom_shell_file_content += <<-MULTI_LINE_STRING
533
+ end
534
+ end
535
+ MULTI_LINE_STRING
536
+ end
537
+
538
+ def custom_widget_file(custom_widget_name, namespace)
539
+ namespace_type = class_name(namespace) == class_name(current_dir_name) ? 'class' : 'module'
540
+
541
+ <<~MULTI_LINE_STRING
542
+ #{namespace_type} #{class_name(namespace)}
543
+ class #{class_name(custom_widget_name)}
544
+ include Glimmer::UI::CustomWidget
545
+
546
+ ## Add options like the following to configure CustomWidget by outside consumers
547
+ #
548
+ # options :custom_text, :background_color
549
+ # option :foreground_color, default: :red
550
+
551
+ ## Use before_body block to pre-initialize variables to use in body
552
+ #
553
+ #
554
+ # before_body {
555
+ #
556
+ # }
557
+
558
+ ## Use after_body block to setup observers for widgets in body
559
+ #
560
+ # after_body {
561
+ #
562
+ # }
563
+
564
+ ## Add widget content under custom widget body
565
+ ##
566
+ ## If you want to add a shell as the top-most widget,
567
+ ## consider creating a custom shell instead
568
+ ## (Glimmer::UI::CustomShell offers shell convenience methods, like show and hide)
569
+ #
570
+ body {
571
+ # Replace example content below with custom widget content
572
+ label {
573
+ background :red
574
+ }
575
+ }
576
+
577
+ end
578
+ end
579
+ MULTI_LINE_STRING
580
+ end
581
+ end
582
+ end