glimmer-dsl-swt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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