skippy 0.3.0.a → 0.4.3.a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c11b52fc9b368e0ba14ead9d714d5e194c312c03056ad27fedbbab607a443fc6
4
- data.tar.gz: ecae267dae0b85c7b5a6d024a0bbc85472e8e92bd3f652349acde9bc7bad7612
3
+ metadata.gz: 991d733215aa26f37690ad9c68cd6d515e648c287584c1acaa91d54ddfb74544
4
+ data.tar.gz: c5da843a98f179df55787c15805b3e0ea7b614bad8dcd450d1b503b0295050f9
5
5
  SHA512:
6
- metadata.gz: 0c691c52f0cd4cf7ef73754a89f07c127301bd097b602957ca6fed8020bd43a82cc0ac025e1a3dc9eaa5ebe125ff46bc95f5b2b9d037638359b56c6d7d4ca758
7
- data.tar.gz: a46e8182a2389a99041fabf6dd224a0faa0239118136f005556f93ca22ca44e1860e667769640547f5bc9051834bc00f8134c7e27b18f7b3fbad4889015e5e5a
6
+ metadata.gz: 4d095d565fc66112b57b16ab89d807ce8b2d3f4a8dc0dd8edd27f5456224a37b906b5b023bf9937fdb8fd533ea18fac75af7fad9ef61f735f003854c225f1ade
7
+ data.tar.gz: 2cc778b7b6b08973447c1868944302c2debb5a3b6e7ba03474873997f45c6b1dcd7af32866aab776740035eb0a4b3050c07dcbb7fa5f41837ee09ce1301fc748
data/.appveyor.yml ADDED
@@ -0,0 +1,32 @@
1
+ version: "{build}-{branch}"
2
+
3
+ branches:
4
+ only:
5
+ - master
6
+ - dev-appveyor
7
+
8
+ cache:
9
+ - vendor/bundle
10
+
11
+ environment:
12
+ matrix:
13
+ - RUBY_VERSION: 25
14
+ - RUBY_VERSION: 26
15
+
16
+ install:
17
+ - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH%
18
+ - gem update --no-document --system 2.7.8
19
+ - gem install bundler --no-document --version="<2.0.0"
20
+ - bundle config --local path vendor/bundle
21
+ - bundle install
22
+ - git submodule update --init --recursive
23
+
24
+ build: off
25
+
26
+ before_test:
27
+ - ruby -v
28
+ - gem -v
29
+ - bundle -v
30
+
31
+ test_script:
32
+ - bundle exec rake
data/.rubocop.yml CHANGED
@@ -9,6 +9,7 @@ AllCops:
9
9
  - 'vendor/**/*'
10
10
  DisplayCopNames: true
11
11
 
12
+
12
13
  Layout/AlignParameters:
13
14
  EnforcedStyle: with_fixed_indentation
14
15
 
@@ -36,6 +37,11 @@ Layout/EndOfLine:
36
37
  Layout/EmptyLinesAroundBlockBody:
37
38
  Enabled: false
38
39
 
40
+
41
+ Naming/RescuedExceptionsVariableName:
42
+ PreferredName: error
43
+
44
+
39
45
  Metrics/AbcSize:
40
46
  Enabled: false
41
47
  Exclude:
@@ -45,6 +51,10 @@ Metrics/ClassLength:
45
51
  Exclude:
46
52
  - test/**/*
47
53
 
54
+ # Too noisy.
55
+ Metrics/CyclomaticComplexity:
56
+ Enabled: false
57
+
48
58
  Metrics/LineLength:
49
59
  Exclude:
50
60
  - features/step_definitions/**/*
@@ -53,6 +63,11 @@ Metrics/MethodLength:
53
63
  Exclude:
54
64
  - test/**/*
55
65
 
66
+ # Too noisy.
67
+ Metrics/PerceivedComplexity:
68
+ Enabled: false
69
+
70
+
56
71
  # Prefer { ... } over do ... end except for control flow and
57
72
  # method defintions. Unfortunatly, no cop configuration for this.
58
73
  # https://github.com/chneukirchen/styleguide/blob/e60de37b478d3f892f6985a58d573016f33f0269/RUBY-STYLE#L63-L67
@@ -82,6 +97,18 @@ Style/Documentation:
82
97
  Style/GuardClause:
83
98
  Enabled: false
84
99
 
100
+ # In the context of the Thor DLS the rocket arrow => reads better.
101
+ Style/HashSyntax:
102
+ Exclude:
103
+ - app/commands/**/*
104
+
105
+ # Some times it reads clearer to not trail if/unless at the end.
106
+ Style/IfUnlessModifier:
107
+ Enabled: false
108
+
109
+ Style/ModuleFunction:
110
+ Enabled: false
111
+
85
112
  # %w and %i etc isn't really intuitive unless you are really familiar with the
86
113
  # syntax. %w seems used often enough. But [:symbol, :foo] reads clearer than
87
114
  # %i(symbol foo).
@@ -89,5 +116,8 @@ Style/SymbolArray:
89
116
  Enabled: False
90
117
 
91
118
  # Add trailing comma so it's easy to duplicate/add lines.
92
- Style/TrailingCommaInLiteral:
119
+ Style/TrailingCommaInArrayLiteral:
120
+ EnforcedStyleForMultiline: consistent_comma
121
+
122
+ Style/TrailingCommaInHashLiteral:
93
123
  EnforcedStyleForMultiline: consistent_comma
data/.vscode/tasks.json CHANGED
@@ -1,16 +1,18 @@
1
1
  {
2
2
  // See https://go.microsoft.com/fwlink/?LinkId=733558
3
3
  // for the documentation about the tasks.json format
4
- "version": "0.1.0",
5
- "command": "bundle",
6
- "isShellCommand": true,
7
- "showOutput": "always",
8
- "echoCommand": true,
9
- "args": ["exec", "rake"],
10
- "tasks": [{
11
- "taskName": "test",
12
- "args": ["TEST=${relativeFile}"],
13
- "isTestCommand": true,
14
- "isBuildCommand": true
15
- }]
4
+ "version": "2.0.0",
5
+ "tasks": [
6
+ {
7
+ "label": "rake test FILE",
8
+ "type": "shell",
9
+ "command": "bundle",
10
+ "args": [
11
+ "exec",
12
+ "rake",
13
+ "TEST=${relativeFile}"
14
+ ],
15
+ "group": "test"
16
+ }
17
+ ]
16
18
  }
data/Gemfile CHANGED
@@ -13,6 +13,7 @@ group :development do
13
13
  # gem 'aruba', git: 'https://github.com/rbld/aruba.git',
14
14
  # branch: 'aruba-win-fix'
15
15
  gem 'pry'
16
- gem 'rubocop', '~> 0.51.0', require: false
16
+ gem 'rubocop', '~> 0.67.2', require: false
17
+ gem 'rubocop-performance', '~> 1.1.0', require: false
17
18
  gem 'webmock', '~> 3.1'
18
19
  end
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Skippy
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/skippy.svg)](https://badge.fury.io/rb/skippy)
3
+ [![Gem Version](https://badge.fury.io/rb/skippy.svg)](https://badge.fury.io/rb/skippy) [![Build status](https://ci.appveyor.com/api/projects/status/qu5nk3t7g5oaymyx/branch/master?svg=true)](https://ci.appveyor.com/project/thomthom/skippy/branch/master)
4
4
 
5
5
  Skippy is a Command Line Interface which aims to automate common developer tasks for SketchUp Ruby extension development.
6
6
 
@@ -14,7 +14,8 @@ Some of the main goals are:
14
14
  - [ ] Add/Remove/Update user templates
15
15
  - [ ] Automate common tasks
16
16
  - [ ] Packaging the extension
17
- - [ ] Start SketchUp in debug mode
17
+ - [x] Launch SketchUp
18
+ - [x] Launch SketchUp in debug mode
18
19
  - [x] Easy interface to add per-project custom commands/tasks
19
20
  - [x] Library dependency management
20
21
  - [x] Pull in third-party modules into extension namespace
@@ -31,7 +32,7 @@ For Windows the easiest way to get Ruby running is using the [Ruby Installer for
31
32
  ## Installation
32
33
 
33
34
  ```bash
34
- gem install skippy
35
+ gem install skippy --pre
35
36
  ```
36
37
 
37
38
  ## Usage
@@ -201,6 +202,30 @@ For more examples, refer to:
201
202
  * [github.com/thomthom/tt-lib](https://github.com/thomthom/tt-lib)
202
203
  * [github.com/thomthom/skippy-test-lib](https://github.com/thomthom/skippy-test-lib)
203
204
 
205
+ ### Launching SketchUp
206
+
207
+ Skippy will attempt to locate your SketchUp installations and offer commands to launch them.
208
+
209
+ These commands provides a cross platform way of launching SketchUp which can be useful in build scripts or IDE automation tasks.
210
+
211
+ (**Note:** Currently Skippy assumes that SketchUp is installed to its default installation directory.)
212
+
213
+ `skippy sketchup:list` will display a list of all known SketchUp versions on the system.
214
+
215
+ ![](https://github.com/thomthom/skippy/wiki/images/skippy-sketchup-list.png)
216
+
217
+ To launch one, use `skippy sketchup:launch VERSION`, for instance:
218
+
219
+ ```
220
+ skippy sketchup:launch 2018
221
+ ```
222
+
223
+ You can also launch SketchUp in debug mode if the [SketchUp Ruby Debugger library](https://github.com/SketchUp/sketchup-ruby-debugger) is installed.
224
+
225
+ ```
226
+ skippy sketchup:debug 2018
227
+ ```
228
+
204
229
  ## Development
205
230
 
206
231
  After checking out the repository, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -5,6 +5,9 @@ Rake::TestTask.new(:test) do |t|
5
5
  t.libs << 'test'
6
6
  t.libs << 'lib'
7
7
  t.test_files = FileList['test/**/*_test.rb']
8
+ # Turning off because Rake 11 >= turns warning on by default.
9
+ # TODO: Clean up the warnings coming from this project and enable.
10
+ t.warning = false
8
11
  end
9
12
 
10
13
  task default: :test
@@ -22,7 +22,7 @@ class Install < Skippy::Command::Group
22
22
  next if library[:version].nil? || library[:source].nil?
23
23
 
24
24
  options = {
25
- requirement: library[:version]
25
+ requirement: library[:version],
26
26
  }
27
27
  options[:branch] = library[:branch] unless library[:branch].nil?
28
28
  lib = project.libraries.install(library[:source], options)
data/app/commands/lib.rb CHANGED
@@ -39,7 +39,8 @@ class Lib < Skippy::Command
39
39
  def install(source)
40
40
  project = Skippy::Project.current_or_fail
41
41
  libraries = project.libraries
42
- library = libraries.install(source, install_options(options)) { |type, message|
42
+ installation_options = install_options(options)
43
+ library = libraries.install(source, installation_options) { |type, message|
43
44
  color = type == :warning ? :red : :yellow
44
45
  say message, color
45
46
  }
data/app/commands/new.rb CHANGED
@@ -38,6 +38,7 @@ class New < Skippy::Command::Group
38
38
  if project.exist?
39
39
  raise Skippy::Error, "A project already exist: #{project.filename}"
40
40
  end
41
+
41
42
  project.namespace = namespace
42
43
  project.name = project.namespace.to_name
43
44
  project.basename = options[:basename] || project.namespace.short_name
@@ -0,0 +1,66 @@
1
+ require 'json'
2
+ require 'stringio'
3
+
4
+ require 'skippy/error'
5
+ require 'skippy/os'
6
+
7
+ class Sketchup < Skippy::Command
8
+
9
+ include Thor::Actions
10
+
11
+ option :port, :type => :numeric, :default => 7000
12
+ desc 'debug VERSION', 'Start SketchUp with Ruby Debugger'
13
+ def debug(version)
14
+ app = find_sketchup(version)
15
+ unless app.can_debug
16
+ raise Skippy::Error, "Debug library not installed for Sketchup #{version}"
17
+ end
18
+
19
+ arguments = ['-rdebug', %("ide port=#{options.port}")]
20
+ Skippy.os.launch_app(app.executable, *arguments)
21
+ end
22
+
23
+ desc 'launch VERSION', 'Start SketchUp'
24
+ def launch(version)
25
+ app = find_sketchup(version)
26
+ Skippy.os.launch_app(app.executable)
27
+ end
28
+
29
+ desc 'list', 'List all known SketchUp versions'
30
+ def list
31
+ say shell.set_color('Known SketchUp versions:', :yellow, true)
32
+ Skippy.os.sketchup_apps.each { |sketchup|
33
+ version = sketchup.version.to_s.ljust(4)
34
+ sketchup_name = "SketchUp #{version}"
35
+ bitness = sketchup.is64bit ? '64bit' : '32bit'
36
+ debug = sketchup.can_debug ? '(debugger)' : ''
37
+ # TODO(thomthom): Use print_table ?
38
+ output = StringIO.new
39
+ output.write ' '
40
+ output.write shell.set_color(sketchup_name, :green, false)
41
+ output.write ' '
42
+ output.write bitness
43
+ output.write ' '
44
+ output.write shell.set_color(debug, :yellow, false)
45
+ say output.string
46
+ }
47
+ end
48
+ default_command(:list)
49
+
50
+ private
51
+
52
+ # @param [Integer] version
53
+ # @return [Skippy::SketchUpApp, nil]
54
+ def find_sketchup(version)
55
+ # Allow shortcuts such as 18 to mean 2018.
56
+ full_version = version.to_i
57
+ full_version += 2000 if (13..99).cover?(full_version)
58
+ app = Skippy.os.sketchup_apps.find { |sketchup|
59
+ sketchup.version == full_version
60
+ }
61
+ raise Skippy::Error, "SketchUp #{version} not found." if app.nil?
62
+
63
+ app
64
+ end
65
+
66
+ end
data/lib/skippy/app.rb CHANGED
@@ -43,6 +43,7 @@ class Skippy::App
43
43
  template_path = templates_source_path.join(entry)
44
44
  next unless template_path.directory?
45
45
  next if %w(. ..).include?(entry.basename.to_s)
46
+
46
47
  result << entry.expand_path(templates_source_path)
47
48
  }
48
49
  result
data/lib/skippy/cli.rb CHANGED
@@ -57,11 +57,12 @@ class Skippy::CLI < Skippy::Command
57
57
  end
58
58
  end
59
59
 
60
+ # rubocop:disable Style/MethodMissingSuper,Style/MissingRespondToMissing
60
61
  # Verbatim copy from Thor::Runner:
61
62
  # If a command is not found on Thor::Runner, method missing is invoked and
62
63
  # Thor::Runner is then responsible for finding the command in all classes.
63
64
  #
64
- def method_missing(meth, *args) # rubocop:disable Style/MethodMissing
65
+ def method_missing(meth, *args)
65
66
  meth = meth.to_s
66
67
  initialize_thorfiles(meth)
67
68
  klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
@@ -69,14 +70,15 @@ class Skippy::CLI < Skippy::Command
69
70
  args.unshift(command) if command
70
71
  klass.start(args, shell: shell)
71
72
  end
73
+ # rubocop:enable Style/MethodMissingSuper,Style/MissingRespondToMissing
72
74
 
73
75
  # Verbatim copy from Thor::Runner:
74
76
  desc 'list [SEARCH]',
75
77
  "List the available #{$PROGRAM_NAME} commands (--substring means .*SEARCH)"
76
78
  method_options substring: :boolean,
77
- group: :string,
78
- all: :boolean,
79
- debug: :boolean
79
+ group: :string,
80
+ all: :boolean,
81
+ debug: :boolean
80
82
  def list(search = '')
81
83
  initialize_thorfiles
82
84
 
@@ -112,8 +114,9 @@ class Skippy::CLI < Skippy::Command
112
114
  def initialize_thorfiles(_relevant_to = nil, _skip_lookup = false)
113
115
  project = Skippy::Project.new(Dir.pwd)
114
116
  return unless project.exist?
117
+
115
118
  project.command_files { |filename|
116
- unless Thor::Base.subclass_files.keys.include?(File.expand_path(filename))
119
+ unless Thor::Base.subclass_files.key?(File.expand_path(filename))
117
120
  begin
118
121
  Thor::Util.load_thorfile(filename, nil, options[:debug])
119
122
  rescue ScriptError, StandardError => error
data/lib/skippy/config.rb CHANGED
@@ -35,6 +35,7 @@ class Skippy::Config < Hash
35
35
  item = get_item(key_path)
36
36
  item = set_item(key_path, []) if item.nil?
37
37
  raise ArgumentError, 'key path is not an Array' unless item.is_a?(Array)
38
+
38
39
  item << value
39
40
  end
40
41
 
@@ -52,6 +53,7 @@ class Skippy::Config < Hash
52
53
 
53
54
  def save
54
55
  raise MissingPathError if path.nil?
56
+
55
57
  export(path)
56
58
  end
57
59
 
@@ -117,9 +119,11 @@ class Skippy::Config < Hash
117
119
  def get_item(key_path)
118
120
  parts = key_parts(key_path)
119
121
  return nil if parts.empty?
122
+
120
123
  item = self
121
124
  parts.each { |key|
122
125
  return nil if item.nil?
126
+
123
127
  item = item[key]
124
128
  }
125
129
  item
@@ -15,6 +15,7 @@ module Skippy::ConfigAccessors
15
15
  class_eval do
16
16
  symbols.each { |symbol|
17
17
  raise TypeError unless symbol.is_a?(Symbol)
18
+
18
19
  define_method(symbol) do
19
20
  value = @config.get(key || symbol, default)
20
21
  value = type.new(value) if type && !value.is_a?(type)
@@ -29,6 +30,7 @@ module Skippy::ConfigAccessors
29
30
  class_eval do
30
31
  symbols.each { |symbol|
31
32
  raise TypeError unless symbol.is_a?(Symbol)
33
+
32
34
  symbol_set = "#{symbol}=".intern
33
35
  define_method(symbol_set) do |value|
34
36
  value = type.new(value) if type && !value.is_a?(type)
@@ -7,6 +7,7 @@ module Skippy::Helpers
7
7
  # @return [Array<Pathname>]
8
8
  def directories(pathname)
9
9
  return [] unless pathname.exist?
10
+
10
11
  pathname.children.select(&:directory?)
11
12
  end
12
13
 
@@ -27,7 +27,7 @@ class Skippy::GitLibraryInstaller < Skippy::LibraryInstaller
27
27
  end
28
28
  begin
29
29
  checkout_branch(git, source.branch) if source.branch
30
- checkout_tag(git, source.requirement) unless edge_version?(source.requirement)
30
+ checkout_tag(git, source.requirement) unless edge_version?(source.requirement) # rubocop:disable Metrics/LineLength
31
31
  rescue Skippy::Error
32
32
  git.checkout(previous_commit) if previous_commit
33
33
  raise
@@ -62,11 +62,12 @@ class Skippy::GitLibraryInstaller < Skippy::LibraryInstaller
62
62
  # @param [Git::Base]
63
63
  # @param [String] branch
64
64
  def checkout_branch(git, branch)
65
- branches = git.braches.map(&:name)
65
+ branches = git.branches.map(&:name)
66
66
  info "Branches: #{branches.inspect}"
67
67
  unless branches.include?(branch)
68
68
  raise Skippy::BranchNotFound, "Found no branch named: '#{branch}'"
69
69
  end
70
+
70
71
  git.checkout(branch)
71
72
  nil
72
73
  end
@@ -77,6 +78,7 @@ class Skippy::GitLibraryInstaller < Skippy::LibraryInstaller
77
78
  tags = Naturally.sort_by(git.tags, :name)
78
79
  tag = latest_version?(version) ? tags.last : resolve_tag(tags, version)
79
80
  raise Skippy::TagNotFound, "Found no version: '#{version}'" if tag.nil?
81
+
80
82
  git.checkout(tag)
81
83
  # Verify the library version with the tagged version.
82
84
  target = path.join(source.lib_path)
@@ -97,6 +99,7 @@ class Skippy::GitLibraryInstaller < Skippy::LibraryInstaller
97
99
  requirement = Gem::Requirement.new(version)
98
100
  tags.reverse.find { |tag|
99
101
  next false unless Gem::Version.correct?(tag.name)
102
+
100
103
  tag_version = Gem::Version.new(tag.name)
101
104
  requirement.satisfied_by?(tag_version)
102
105
  }
@@ -13,6 +13,7 @@ class Skippy::LibModule
13
13
  def initialize(library, path)
14
14
  @path = Pathname.new(path)
15
15
  raise ModuleNotFoundError, @path.to_s unless @path.file?
16
+
16
17
  @library = library
17
18
  end
18
19
 
@@ -40,6 +40,7 @@ class Skippy::LibrarySource
40
40
  # @return [String, nil]
41
41
  def requirement
42
42
  return nil if @options[:requirement].nil?
43
+
43
44
  # Normalize the version requirement pattern.
44
45
  parts = Gem::Requirement.parse(@options[:requirement])
45
46
  # .parse will from '1.2.3' return ['=', '1.2.3']. Don't need that.
@@ -117,7 +118,10 @@ class Skippy::LibrarySource
117
118
  # @param [String] source
118
119
  # @return [String]
119
120
  def resolve_from_git_uri(source)
120
- uri = URI.parse(source)
121
+ # This can be a local Windows path, normalize path separators to allow the
122
+ # path to be parsed.
123
+ normalized = source.tr('\\', '/')
124
+ uri = URI.parse(normalized)
121
125
  # When logged in, BitBucket will display a URI with the user's username.
122
126
  uri.user = ''
123
127
  uri.to_s
@@ -28,8 +28,10 @@ class Skippy::Library
28
28
  @path = Pathname.new(path)
29
29
  raise LibraryNotFoundError, @path.to_s unless @path.directory?
30
30
  raise LibraryNotFoundError, config_file.to_s unless config_file.exist?
31
+
31
32
  @config = Skippy::Config.load(config_file)
32
33
  raise LibraryNotFoundError, 'Not a Skippy Library' unless @config[:library]
34
+
33
35
  @source = source
34
36
  end
35
37
 
@@ -29,6 +29,7 @@ class Skippy::LibraryManager
29
29
  # @param [Skippy::Project] project
30
30
  def initialize(project)
31
31
  raise TypeError, 'expected a Project' unless project.is_a?(Skippy::Project)
32
+
32
33
  @project = project
33
34
  @libraries = SortedSet.new(discover_libraries)
34
35
  end
@@ -56,8 +57,10 @@ class Skippy::LibraryManager
56
57
  if library_name.nil? || module_name.nil?
57
58
  raise ArgumentError, 'expected a module path'
58
59
  end
60
+
59
61
  library = find_library(library_name)
60
62
  return nil if library.nil?
63
+
61
64
  library.modules.find { |mod| mod.basename.casecmp(module_name).zero? }
62
65
  end
63
66
 
@@ -77,6 +80,7 @@ class Skippy::LibraryManager
77
80
  # @return [Skippy::Library]
78
81
  def install(source, options = {})
79
82
  raise Skippy::Project::ProjectNotSavedError unless project.exist?
83
+
80
84
  lib_source = Skippy::LibrarySource.new(project, source, options)
81
85
 
82
86
  installer = get_installer(lib_source)
@@ -99,8 +103,10 @@ class Skippy::LibraryManager
99
103
  # @return [Skippy::Library]
100
104
  def uninstall(lib)
101
105
  raise Skippy::Project::ProjectNotSavedError unless project.exist?
106
+
102
107
  library = lib.is_a?(Skippy::Library) ? lib : find_library(lib)
103
108
  raise Skippy::LibraryNotFound, 'Library not found' if library.nil?
109
+
104
110
  # Uninstall modules first - using the module manager.
105
111
  vendor_path = project.modules.vendor_path
106
112
  vendor_module_path = vendor_path.join(library.name)
@@ -113,9 +119,11 @@ class Skippy::LibraryManager
113
119
  vendor_path.rmdir
114
120
  end
115
121
  raise 'Unable to remove vendor modules' if vendor_module_path.exist?
122
+
116
123
  # Now the library itself is safe to remove.
117
124
  library.path.rmtree if library.path.exist?
118
125
  raise 'Unable to remove library' if library.path.exist?
126
+
119
127
  @libraries.delete(library)
120
128
  library
121
129
  end
@@ -17,6 +17,7 @@ class Skippy::ModuleManager
17
17
  # @param [Skippy::Project] project
18
18
  def initialize(project)
19
19
  raise TypeError, 'expected a Project' unless project.is_a?(Skippy::Project)
20
+
20
21
  @project = project
21
22
  @modules = SortedSet.new(discover_modules)
22
23
  end
@@ -48,6 +49,7 @@ class Skippy::ModuleManager
48
49
  # @return [Skippy::LibModule]
49
50
  def use(module_name)
50
51
  raise Skippy::Project::ProjectNotSavedError unless project.exist?
52
+
51
53
  lib_module = project.libraries.find_module_or_fail(module_name)
52
54
 
53
55
  source = lib_module.path
@@ -63,6 +65,7 @@ class Skippy::ModuleManager
63
65
  # @return [Array<Skippy::LibModule>]
64
66
  def update(library)
65
67
  raise Skippy::Project::ProjectNotSavedError unless project.exist?
68
+
66
69
  installed = select { |mod| mod.library.name.casecmp(library.name).zero? }
67
70
  installed.each { |mod| use(mod.name) }
68
71
  installed
@@ -72,6 +75,7 @@ class Skippy::ModuleManager
72
75
  # @return [Skippy::LibModule]
73
76
  def remove(module_name)
74
77
  raise Skippy::Project::ProjectNotSavedError unless project.exist?
78
+
75
79
  lib_module = project.libraries.find_module_or_fail(module_name)
76
80
 
77
81
  target = vendor_path.join(lib_module.library.name, lib_module.path.basename)
@@ -103,9 +107,11 @@ class Skippy::ModuleManager
103
107
  project.libraries.each { |library|
104
108
  library_vendor_path = vendor_path.join(library.name)
105
109
  next unless library_vendor_path.directory?
110
+
106
111
  library_vendor_path.each_child { |module_file|
107
112
  next unless module_file.file?
108
113
  next unless module_file.extname.casecmp('.rb').zero?
114
+
109
115
  modules << Skippy::LibModule.new(library, module_file)
110
116
  }
111
117
  }
@@ -122,6 +128,7 @@ class Skippy::ModuleManager
122
128
  basename = source.basename('.*')
123
129
  source_support_folder = source.parent.join(basename)
124
130
  return unless source_support_folder.directory?
131
+
125
132
  target_support_folder = target.parent.join(basename)
126
133
  copy_directory(lib_module, source_support_folder, target_support_folder)
127
134
  end
@@ -133,6 +140,7 @@ class Skippy::ModuleManager
133
140
  Dir.glob("#{source_path}/**/*") { |filename|
134
141
  source = Pathname.new(filename)
135
142
  next unless source.file?
143
+
136
144
  relative_path = source.relative_path_from(source_path)
137
145
  target = target_path.join(relative_path)
138
146
  copy_file(lib_module, source, target)
@@ -150,7 +158,7 @@ class Skippy::ModuleManager
150
158
  transform_module(content)
151
159
  File.write(target, content)
152
160
  else
153
- File.copy(source, target)
161
+ FileUtils.copy(source, target)
154
162
  end
155
163
  end
156
164
 
@@ -164,7 +172,7 @@ class Skippy::ModuleManager
164
172
  content
165
173
  end
166
174
 
167
- LIB_REQUIRE_PATTERN = %r{(\brequire ["'])(modules)(/[^"']*["'])}
175
+ LIB_REQUIRE_PATTERN = %r{(\brequire ["'])(modules)(/[^"']*["'])}.freeze
168
176
 
169
177
  # Transform the require statements to the target destination.
170
178
  #
@@ -6,6 +6,7 @@ class Skippy::Namespace
6
6
  unless valid?(namespace)
7
7
  raise Skippy::Error, "'#{namespace}' is not a valid Ruby namespace"
8
8
  end
9
+
9
10
  @namespace = namespace
10
11
  end
11
12
 
@@ -24,6 +25,7 @@ class Skippy::Namespace
24
25
  def short_name
25
26
  items = to_a
26
27
  return to_s unless items.size > 1
28
+
27
29
  initials = items.first.scan(/[[:upper:]]/)
28
30
  prefix = initials.size > 1 ? initials.join : items.first[0, 2]
29
31
  "#{prefix}_#{items.last}"
data/lib/skippy/os.rb ADDED
@@ -0,0 +1,17 @@
1
+ module Skippy
2
+
3
+ if RUBY_PLATFORM =~ /darwin/
4
+ require 'skippy/os/mac'
5
+ OS = Skippy::OSMac
6
+ else
7
+ require 'skippy/os/win'
8
+ OS = Skippy::OSWin
9
+ end
10
+
11
+ @os = OS.new
12
+
13
+ def self.os
14
+ @os
15
+ end
16
+
17
+ end
@@ -0,0 +1,33 @@
1
+ class Skippy::OSCommon
2
+
3
+ # @param [String] command
4
+ def execute_command(command)
5
+ # Something with a Thor application like skippy get the 'RUBYLIB'
6
+ # environment set which prevents SketchUp from finding its StdLib
7
+ # directories. (At least under Windows.) This relates to child processes
8
+ # inheriting the environment variables of its parent.
9
+ # To work around this we unset RUBYLIB before launching SketchUp. This
10
+ # doesn't affect skippy as it's about to exit as soon as SketchUp starts
11
+ # any way.
12
+ ENV['RUBYLIB'] = nil if ENV['RUBYLIB']
13
+ id = spawn(command)
14
+ Process.detach(id)
15
+ end
16
+
17
+ # @param [String] path
18
+ def launch_app(path, *args) # rubocop:disable Lint/UnusedMethodArgument
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def sketchup_apps
23
+ raise NotImplementedError
24
+ end
25
+
26
+ # @param [String] path
27
+ # @return [Integer, nil]
28
+ def sketchup_version_from_path(path)
29
+ match = File.basename(path).match(/[0-9.]+/)
30
+ match ? match[0].to_i : nil
31
+ end
32
+
33
+ end
@@ -0,0 +1,34 @@
1
+ require 'skippy/os/common'
2
+ require 'skippy/sketchup/app'
3
+
4
+ class Skippy::OSMac < Skippy::OSCommon
5
+
6
+ # @param [String] executable_path
7
+ def launch_app(executable_path, *args)
8
+ command = %(open -a "#{executable_path}")
9
+ unless args.empty?
10
+ command << " --args #{args.join(' ')}"
11
+ end
12
+ execute_command(command)
13
+ end
14
+
15
+ def sketchup_apps
16
+ apps = []
17
+ pattern = '/Applications/SketchUp */'
18
+ Dir.glob(pattern) { |path|
19
+ app = File.join(path, 'SketchUp.app')
20
+ debug_lib = File.join(app, 'Contents/Frameworks/SURubyDebugger.dylib')
21
+ version = sketchup_version_from_path(path)
22
+ next unless version
23
+
24
+ apps << Skippy::SketchUpApp.from_hash(
25
+ executable: app,
26
+ version: version,
27
+ can_debug: File.exist?(debug_lib),
28
+ is64bit: version > 2015
29
+ )
30
+ }
31
+ apps.sort_by(&:version)
32
+ end
33
+
34
+ end
@@ -0,0 +1,58 @@
1
+ require 'skippy/os/common'
2
+ require 'skippy/sketchup/app'
3
+
4
+ class Skippy::OSWin < Skippy::OSCommon
5
+
6
+ # Note: This is not a good indication to 32bit bs 64bit. It's a naive
7
+ # assumption that will fail when SketchUp is installed to a
8
+ # non-standard location.
9
+ SYSTEM_32BIT = ENV['ProgramFiles(x86)'].nil? && ENV['ProgramW6432'].nil?
10
+ SYSTEM_64BIT = !SYSTEM_32BIT
11
+
12
+ PROGRAM_FILES_64BIT = File.expand_path(ENV['ProgramW6432'])
13
+
14
+ # @param [String] executable_path
15
+ def launch_app(executable_path, *args)
16
+ command = %("#{executable_path}")
17
+ unless args.empty?
18
+ command << " #{args.join(' ')}"
19
+ end
20
+ execute_command(command)
21
+ end
22
+
23
+ def sketchup_apps
24
+ # TODO(thomthom): Find by registry information.
25
+ apps = []
26
+ program_files_paths.each { |program_files|
27
+ pattern = "#{program_files}/{@Last Software,Google,SketchUp}/*SketchUp *"
28
+ Dir.glob(pattern) { |path|
29
+ exe = File.join(path, 'SketchUp.exe')
30
+ debug_dll = File.join(path, 'SURubyDebugger.dll')
31
+ version = sketchup_version_from_path(path)
32
+ next unless version
33
+
34
+ apps << Skippy::SketchUpApp.from_hash(
35
+ executable: exe,
36
+ version: version,
37
+ can_debug: File.exist?(debug_dll),
38
+ is64bit: SYSTEM_64BIT && path.start_with?("#{PROGRAM_FILES_64BIT}/")
39
+ )
40
+ }
41
+ }
42
+ apps.sort_by(&:version)
43
+ end
44
+
45
+ private
46
+
47
+ def program_files_paths
48
+ paths = []
49
+ if SYSTEM_64BIT
50
+ paths << File.expand_path(ENV['ProgramFiles(x86)'])
51
+ paths << File.expand_path(ENV['ProgramW6432'])
52
+ else
53
+ paths << File.expand_path(ENV['ProgramFiles'])
54
+ end
55
+ paths
56
+ end
57
+
58
+ end
@@ -36,6 +36,7 @@ class Skippy::Project
36
36
  def self.current_or_fail
37
37
  project = current
38
38
  raise ProjectNotFoundError, project.filename unless project.exist?
39
+
39
40
  project
40
41
  end
41
42
 
@@ -108,8 +109,8 @@ class Skippy::Project
108
109
  end
109
110
 
110
111
  # @return [String]
111
- def to_json
112
- JSON.pretty_generate(@config)
112
+ def to_json(*args)
113
+ JSON.pretty_generate(@config, *args)
113
114
  end
114
115
 
115
116
  private
@@ -141,6 +142,7 @@ class Skippy::Project
141
142
  project_file = pathname.join(PROJECT_FILENAME)
142
143
  return pathname if project_file.exist?
143
144
  break if pathname.root?
145
+
144
146
  pathname = pathname.parent
145
147
  end
146
148
  nil
@@ -0,0 +1,11 @@
1
+ module Skippy
2
+
3
+ SketchUpApp = Struct.new(:executable, :version, :can_debug, :is64bit) do
4
+
5
+ def self.from_hash(hash)
6
+ new(*hash.values_at(*members))
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -1,5 +1,5 @@
1
1
  module Skippy
2
2
 
3
- VERSION = '0.3.0.a'.freeze
3
+ VERSION = '0.4.3.a'.freeze
4
4
 
5
5
  end
data/skippy.gemspec CHANGED
@@ -28,8 +28,8 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency 'naturally', '~> 2.1'
29
29
  spec.add_dependency 'thor', '~> 0.19'
30
30
 
31
- spec.add_development_dependency 'bundler', '~> 1.13'
32
- spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'bundler', '>= 1.15.0', '< 3.0'
32
+ spec.add_development_dependency 'rake', '~> 12.3.3'
33
33
  spec.add_development_dependency 'minitest', '~> 5.0'
34
34
  # TODO(thomthom): Need to lock to 2.3 because 2.4 fails with the custom
35
35
  # aruba build.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skippy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0.a
4
+ version: 0.4.3.a
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Thomassen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-19 00:00:00.000000000 Z
11
+ date: 2021-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
@@ -56,30 +56,36 @@ dependencies:
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.15.0
62
+ - - "<"
60
63
  - !ruby/object:Gem::Version
61
- version: '1.13'
64
+ version: '3.0'
62
65
  type: :development
63
66
  prerelease: false
64
67
  version_requirements: !ruby/object:Gem::Requirement
65
68
  requirements:
66
- - - "~>"
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 1.15.0
72
+ - - "<"
67
73
  - !ruby/object:Gem::Version
68
- version: '1.13'
74
+ version: '3.0'
69
75
  - !ruby/object:Gem::Dependency
70
76
  name: rake
71
77
  requirement: !ruby/object:Gem::Requirement
72
78
  requirements:
73
79
  - - "~>"
74
80
  - !ruby/object:Gem::Version
75
- version: '10.0'
81
+ version: 12.3.3
76
82
  type: :development
77
83
  prerelease: false
78
84
  version_requirements: !ruby/object:Gem::Requirement
79
85
  requirements:
80
86
  - - "~>"
81
87
  - !ruby/object:Gem::Version
82
- version: '10.0'
88
+ version: 12.3.3
83
89
  - !ruby/object:Gem::Dependency
84
90
  name: minitest
85
91
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +137,7 @@ executables:
131
137
  extensions: []
132
138
  extra_rdoc_files: []
133
139
  files:
140
+ - ".appveyor.yml"
134
141
  - ".editorconfig"
135
142
  - ".gitignore"
136
143
  - ".gitmodules"
@@ -159,6 +166,7 @@ files:
159
166
  - app/commands/install.rb
160
167
  - app/commands/lib.rb
161
168
  - app/commands/new.rb
169
+ - app/commands/sketchup.rb
162
170
  - app/commands/template.rb
163
171
  - app/resources/commands/example.rb
164
172
  - app/templates/standard/%ext_name%.rb.tt
@@ -226,14 +234,19 @@ files:
226
234
  - lib/skippy/library_manager.rb
227
235
  - lib/skippy/module_manager.rb
228
236
  - lib/skippy/namespace.rb
237
+ - lib/skippy/os.rb
238
+ - lib/skippy/os/common.rb
239
+ - lib/skippy/os/mac.rb
240
+ - lib/skippy/os/win.rb
229
241
  - lib/skippy/project.rb
242
+ - lib/skippy/sketchup/app.rb
230
243
  - lib/skippy/version.rb
231
244
  - skippy.gemspec
232
245
  homepage: https://github.com/thomthom/skippy
233
246
  licenses:
234
247
  - MIT
235
248
  metadata: {}
236
- post_install_message:
249
+ post_install_message:
237
250
  rdoc_options: []
238
251
  require_paths:
239
252
  - lib
@@ -248,9 +261,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
261
  - !ruby/object:Gem::Version
249
262
  version: 1.3.1
250
263
  requirements: []
251
- rubyforge_project:
252
- rubygems_version: 2.7.3
253
- signing_key:
264
+ rubygems_version: 3.0.3
265
+ signing_key:
254
266
  specification_version: 4
255
267
  summary: CLI development tool for SketchUp extensions.
256
268
  test_files: []