skippy 0.1.1.a → 0.2.0.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +14 -0
  3. data/.gitignore +5 -0
  4. data/.idea/.rakeTasks +7 -0
  5. data/.idea/codeStyleSettings.xml +9 -0
  6. data/.idea/encodings.xml +6 -0
  7. data/.idea/inspectionProfiles/Project_Default.xml +8 -0
  8. data/.idea/misc.xml +4 -0
  9. data/.idea/modules.xml +8 -0
  10. data/.idea/runConfigurations/All_Features.xml +32 -0
  11. data/.idea/runConfigurations/test__skippy.xml +21 -0
  12. data/.idea/skippy.iml +83 -0
  13. data/.idea/vcs.xml +6 -0
  14. data/.vscode/launch.json +61 -0
  15. data/.vscode/settings.json +3 -2
  16. data/.vscode/tasks.json +16 -0
  17. data/Gemfile +5 -0
  18. data/Rakefile +4 -4
  19. data/app/boot.rb +1 -1
  20. data/app/commands/debug.rb +2 -1
  21. data/app/commands/lib.rb +46 -0
  22. data/app/commands/new.rb +4 -3
  23. data/app/commands/template.rb +3 -3
  24. data/app/resources/commands/example.rb +1 -1
  25. data/app/templates/standard/%ext_name%.rb.tt +1 -1
  26. data/app/templates/webdialog/{extension.rb.erb → %ext_name%.rb.tt} +1 -1
  27. data/app/templates/webdialog/{extension → %ext_name%}/html/dialog.html +0 -0
  28. data/app/templates/webdialog/{extension/main.rb.erb → %ext_name%/main.rb.tt} +0 -0
  29. data/bin/aruba +17 -0
  30. data/bin/cucumber +17 -0
  31. data/bin/htmldiff +17 -0
  32. data/bin/ldiff +17 -0
  33. data/cSpell.json +18 -0
  34. data/fixtures/my_lib/skippy.json +5 -0
  35. data/fixtures/my_lib/src/command.rb +4 -0
  36. data/fixtures/my_lib/src/geometry.rb +4 -0
  37. data/fixtures/my_lib/src/tool.rb +4 -0
  38. data/fixtures/my_project/skippy.json +8 -0
  39. data/fixtures/my_project/skippy/commands/example.rb +14 -0
  40. data/fixtures/my_project/src/hello_world.rb +47 -0
  41. data/fixtures/my_project/src/hello_world/extension.json +10 -0
  42. data/fixtures/my_project/src/hello_world/main.rb +21 -0
  43. data/lib/skippy.rb +7 -3
  44. data/lib/skippy/app.rb +7 -5
  45. data/lib/skippy/cli.rb +12 -12
  46. data/lib/skippy/config.rb +135 -0
  47. data/lib/skippy/config_accessors.rb +43 -0
  48. data/lib/skippy/error.rb +1 -1
  49. data/lib/skippy/helpers/file.rb +14 -0
  50. data/lib/skippy/lib_module.rb +47 -0
  51. data/lib/skippy/library.rb +57 -0
  52. data/lib/skippy/library_manager.rb +75 -0
  53. data/lib/skippy/module_manager.rb +103 -0
  54. data/lib/skippy/namespace.rb +7 -3
  55. data/lib/skippy/project.rb +55 -26
  56. data/lib/skippy/version.rb +1 -1
  57. data/skippy.gemspec +14 -12
  58. metadata +69 -8
  59. data/lib/skippy/skippy.rb +0 -9
@@ -8,18 +8,18 @@ class Template < Skippy::Command
8
8
  say ' No templates found'
9
9
  else
10
10
  templates.each { |template|
11
- say " #{template}", :green
11
+ say " #{template.basename}", :green
12
12
  }
13
13
  end
14
14
  end
15
15
  default_command(:list)
16
16
 
17
- desc 'install', 'Install a new template'
17
+ desc 'install SOURCE', 'Install a new template'
18
18
  def install(source)
19
19
  raise Skippy::Error, 'Not implemented'
20
20
  end
21
21
 
22
- desc 'remove', 'Remove an installed template'
22
+ desc 'remove TEMPLATE', 'Remove an installed template'
23
23
  def remove(template_name)
24
24
  raise Skippy::Error, 'Not implemented'
25
25
  end
@@ -7,7 +7,7 @@ class Hello < Skippy::Command
7
7
  default_command(:world)
8
8
 
9
9
  desc 'universe', 'Greets the universe in general'
10
- def universe(person)
10
+ def universe
11
11
  say "DARK IN HERE, ISN'T IT?"
12
12
  end
13
13
 
@@ -31,7 +31,7 @@ require 'sketchup.rb'
31
31
  EXTENSION = ::JSON.parse(extension_json, symbolize_names: true).freeze
32
32
 
33
33
  unless file_loaded?(__FILE__)
34
- loader = File.join(PATH, 'bootstrap')
34
+ loader = File.join(PATH, 'main')
35
35
  @extension = SketchupExtension.new(EXTENSION[:name], loader)
36
36
  @extension.description = EXTENSION[:description]
37
37
  @extension.version = EXTENSION[:version]
@@ -31,7 +31,7 @@ require 'sketchup.rb'
31
31
  EXTENSION = ::JSON.parse(extension_json, symbolize_names: true).freeze
32
32
 
33
33
  unless file_loaded?(__FILE__)
34
- loader = File.join(PATH, 'bootstrap')
34
+ loader = File.join(PATH, 'main')
35
35
  @extension = SketchupExtension.new(EXTENSION[:name], loader)
36
36
  @extension.description = EXTENSION[:description]
37
37
  @extension.version = EXTENSION[:version]
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'aruba' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("aruba", "aruba")
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'cucumber' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("cucumber", "cucumber")
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'htmldiff' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("diff-lcs", "htmldiff")
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'ldiff' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("diff-lcs", "ldiff")
@@ -0,0 +1,18 @@
1
+ // cSpell Settings
2
+ {
3
+ // Version of the setting file. Always 0.1
4
+ "version": "0.1",
5
+ // language - current active spelling language
6
+ "language": "en",
7
+ // words - list of words to be always considered correct
8
+ "words": [
9
+ "namespace",
10
+ "yieldparam"
11
+ ],
12
+ // flagWords - list of words to be always considered incorrect
13
+ // This is useful for offensive words and common spelling errors.
14
+ // For example "hte" should be "the"
15
+ "flagWords": [
16
+ "hte"
17
+ ]
18
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "library": true,
3
+ "name": "My Shiny Library",
4
+ "version": "1.2.3"
5
+ }
@@ -0,0 +1,4 @@
1
+ module SkippyLib
2
+ class Command
3
+ end
4
+ end # module
@@ -0,0 +1,4 @@
1
+ module SkippyLib
2
+ class Geometry
3
+ end
4
+ end # module
@@ -0,0 +1,4 @@
1
+ module SkippyLib
2
+ class Tool
3
+ end
4
+ end # module
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "Hello World",
3
+ "description": "",
4
+ "namespace": "Example::HelloWorld",
5
+ "author": "Unknown",
6
+ "copyright": "Copyright (c) 2017",
7
+ "license": "None"
8
+ }
@@ -0,0 +1,14 @@
1
+ class Hello < Skippy::Command
2
+
3
+ desc 'world PERSON', 'Oh, hi there!'
4
+ def world(person)
5
+ say "Hello #{person}"
6
+ end
7
+ default_command(:world)
8
+
9
+ desc 'universe', 'Greets the universe in general'
10
+ def universe
11
+ say "DARK IN HERE, ISN'T IT?"
12
+ end
13
+
14
+ end
@@ -0,0 +1,47 @@
1
+ #-------------------------------------------------------------------------------
2
+ #
3
+ # Author: Unknown
4
+ # Copyright: Copyright (c) 2017
5
+ # License: None
6
+ #
7
+ #-------------------------------------------------------------------------------
8
+
9
+ require 'json'
10
+
11
+ require 'extensions.rb'
12
+ require 'sketchup.rb'
13
+
14
+ module Example
15
+ module HelloWorld
16
+
17
+ file = __FILE__.dup
18
+ # Account for Ruby encoding bug under Windows.
19
+ file.force_encoding('UTF-8') if file.respond_to?(:force_encoding)
20
+ # Support folder should be named the same as the root .rb file.
21
+ folder_name = File.basename(file, '.*')
22
+
23
+ # Path to the root .rb file (this file).
24
+ PATH_ROOT = File.dirname(file).freeze
25
+
26
+ # Path to the support folder.
27
+ PATH = File.join(PATH_ROOT, folder_name).freeze
28
+
29
+ # Extension information.
30
+ extension_json_file = File.join(PATH, 'extension.json')
31
+ extension_json = File.read(extension_json_file)
32
+ EXTENSION = ::JSON.parse(extension_json, symbolize_names: true).freeze
33
+
34
+ unless file_loaded?(__FILE__)
35
+ loader = File.join(PATH, 'main')
36
+ @extension = SketchupExtension.new(EXTENSION[:name], loader)
37
+ @extension.description = EXTENSION[:description]
38
+ @extension.version = EXTENSION[:version]
39
+ @extension.copyright = EXTENSION[:copyright]
40
+ @extension.creator = EXTENSION[:creator]
41
+ Sketchup.register_extension(@extension, true)
42
+ end
43
+
44
+ end # module HelloWorld
45
+ end # module Example
46
+
47
+ file_loaded(__FILE__)
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "Hello World",
3
+ "description": "",
4
+ "creator": "Unknown",
5
+ "copyright": "Copyright (c) 2017",
6
+ "license": "None",
7
+ "product_id": "Example_HelloWorld",
8
+ "version": "0.1.0",
9
+ "build": "1"
10
+ }
@@ -0,0 +1,21 @@
1
+ require 'sketchup.rb'
2
+
3
+ module Example::HelloWorld
4
+
5
+ unless file_loaded?(__FILE__)
6
+ menu = UI.menu('Plugins').add_submenu(EXTENSION[:name])
7
+ menu.add_item('Make Magic') { self.make_magic }
8
+ menu.add_separator
9
+ menu.add_item('Help...') { self.open_help }
10
+ file_loaded(__FILE__)
11
+ end
12
+
13
+ def self.make_magic
14
+ # Do magic here...
15
+ end
16
+
17
+ def self.open_help
18
+ UI.openURL(EXTENSION[:url])
19
+ end
20
+
21
+ end # module
@@ -1,5 +1,9 @@
1
- require "skippy/version"
1
+ require 'skippy/version'
2
2
 
3
3
  module Skippy
4
- # Your code goes here...
5
- end
4
+
5
+ class << self
6
+ attr_accessor :app
7
+ end
8
+
9
+ end # module
@@ -1,8 +1,8 @@
1
1
  require 'pathname'
2
2
 
3
+ require 'skippy'
3
4
  require 'skippy/command'
4
5
  require 'skippy/group'
5
- require 'skippy/skippy'
6
6
 
7
7
  class Skippy::App
8
8
 
@@ -11,6 +11,7 @@ class Skippy::App
11
11
  def self.boot(boot_loader_path)
12
12
  Skippy.app = Skippy::App.new(boot_loader_path)
13
13
  Skippy.app.boot
14
+ Skippy.app
14
15
  end
15
16
 
16
17
  attr_reader :path
@@ -35,27 +36,28 @@ class Skippy::App
35
36
  Pathname.new(File.join(path, 'templates'))
36
37
  end
37
38
 
39
+ # @return [Array<Pathname>]
38
40
  def templates
39
41
  result = []
40
42
  templates_source_path.entries.each { |entry|
41
43
  template_path = templates_source_path.join(entry)
42
44
  next unless template_path.directory?
43
- next if %[. ..].include?(entry.basename.to_s)
44
- result << entry
45
+ next if %w[. ..].include?(entry.basename.to_s)
46
+ result << entry.expand_path(templates_source_path)
45
47
  }
46
48
  result
47
49
  end
48
50
 
49
51
  private
50
52
 
51
- # @return [Array<String>] loaded files
52
53
  def boot_commands
53
54
  # Load the default skippy commands.
54
55
  path_commands = File.join(path, 'commands')
55
56
  commands_pattern = File.join(path_commands, '*.rb')
56
57
  Dir.glob(commands_pattern) { |filename|
58
+ # noinspection RubyResolve
57
59
  require filename
58
60
  }
59
61
  end
60
62
 
61
- end
63
+ end
@@ -31,11 +31,11 @@ class Skippy::CLI < Skippy::Command
31
31
 
32
32
  end # Class methods
33
33
 
34
- map "-v" => :version
34
+ map '-v' => :version
35
35
 
36
36
  default_command :list
37
37
 
38
- desc "version", "Show Skippy version"
38
+ desc 'version', 'Show Skippy version'
39
39
  def version
40
40
  display_app_banner
41
41
  end
@@ -48,7 +48,7 @@ class Skippy::CLI < Skippy::Command
48
48
  initialize_thorfiles(meth)
49
49
  klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
50
50
  self.class.handle_no_command_error(command, false) if klass.nil?
51
- klass.start(["-h", command].compact, :shell => shell)
51
+ klass.start(['-h', command].compact, :shell => shell)
52
52
  else
53
53
  super
54
54
  end
@@ -68,14 +68,14 @@ class Skippy::CLI < Skippy::Command
68
68
  end
69
69
 
70
70
  # Verbatim copy from Thor::Runner:
71
- desc "list [SEARCH]", "List the available #{$PROGRAM_NAME} commands (--substring means .*SEARCH)"
71
+ desc 'list [SEARCH]', "List the available #{$PROGRAM_NAME} commands (--substring means .*SEARCH)"
72
72
  method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
73
- def list(search = "")
73
+ def list(search = '')
74
74
  initialize_thorfiles
75
75
 
76
- search = ".*#{search}" if options["substring"]
76
+ search = ".*#{search}" if options['substring']
77
77
  search = /^#{search}.*/i
78
- group = options[:group] || "standard"
78
+ group = options[:group] || 'standard'
79
79
 
80
80
  klasses = Thor::Base.subclasses.select do |k|
81
81
  (options[:all] || k.group == group) && k.namespace =~ search
@@ -120,7 +120,7 @@ class Skippy::CLI < Skippy::Command
120
120
  end
121
121
 
122
122
  # Based on Thor::Runner:
123
- def display_klasses(with_modules = false, show_internal = false, klasses = Thor::Base.subclasses)
123
+ def display_klasses(_with_modules = false, show_internal = false, klasses = Thor::Base.subclasses)
124
124
  unless show_internal
125
125
  klasses -= [
126
126
  Thor, Thor::Runner, Thor::Group,
@@ -135,7 +135,7 @@ class Skippy::CLI < Skippy::Command
135
135
 
136
136
  # Get classes which inherit from Thor
137
137
  (klasses - groups).each { |k|
138
- list[k.namespace.split(":").first] += k.printable_commands(false)
138
+ list[k.namespace.split(':').first] += k.printable_commands(false)
139
139
  }
140
140
 
141
141
  # Get classes which inherit from Thor::Base
@@ -156,7 +156,7 @@ class Skippy::CLI < Skippy::Command
156
156
 
157
157
  # Order namespaces with default coming first
158
158
  list = list.sort { |a, b|
159
- a[0].sub(/^default/, "") <=> b[0].sub(/^default/, "")
159
+ a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '')
160
160
  }
161
161
  list.each { |n, commands|
162
162
  display_commands(n, commands, col_width) unless commands.empty?
@@ -189,10 +189,10 @@ class Skippy::CLI < Skippy::Command
189
189
  labels = %w[Modules Namespaces]
190
190
 
191
191
  info << labels
192
- info << ["-" * labels[0].size, "-" * labels[1].size]
192
+ info << ['-' * labels[0].size, '-' * labels[1].size]
193
193
 
194
194
  print_table info
195
- say ""
195
+ say ''
196
196
  end
197
197
 
198
198
  end
@@ -0,0 +1,135 @@
1
+ require 'json'
2
+ require 'pathname'
3
+
4
+ require 'skippy/error'
5
+
6
+ class Skippy::Config < Hash
7
+
8
+ attr_accessor :path
9
+
10
+ class MissingPathError < Skippy::Error; end
11
+
12
+ def self.load(path, defaults = {})
13
+ if path.exist?
14
+ json = File.read(path)
15
+ config = JSON.parse(json,
16
+ symbolize_names: true,
17
+ object_class: self
18
+ )
19
+ else
20
+ config = self.new
21
+ end
22
+ # Need to merge nested defaults.
23
+ config.merge!(defaults) { |_key, value, default|
24
+ if value.is_a?(Hash) && default.is_a?(Hash)
25
+ # Deep merge in order to merge nested hashes.
26
+ # Note: This currently doesn't merge arrays.
27
+ # http://stackoverflow.com/a/9381776/486990
28
+ merger = proc { |_k, v1, v2|
29
+ Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2
30
+ }
31
+ default.merge(value, &merger)
32
+ else
33
+ value || default
34
+ end
35
+ }
36
+ config.path = path
37
+ config
38
+ end
39
+
40
+ def get(key_path, default = nil)
41
+ get_item(key_path) || default
42
+ end
43
+
44
+ def set(key_path, value)
45
+ set_item(key_path, value)
46
+ end
47
+
48
+ def push(key_path, value)
49
+ item = get_item(key_path)
50
+ item = set_item(key_path, []) if item.nil?
51
+ raise ArgumentError, 'key path is not an Array' unless item.is_a?(Array)
52
+ item << value
53
+ end
54
+
55
+ def export(target_path)
56
+ json = JSON.pretty_generate(self)
57
+ File.write(target_path, json)
58
+ nil
59
+ end
60
+
61
+ def save_as(target_path)
62
+ export(target_path)
63
+ @path = target_path
64
+ nil
65
+ end
66
+
67
+ def save
68
+ raise MissingPathError if path.nil?
69
+ export(path)
70
+ end
71
+
72
+ def path=(new_path)
73
+ @path = Pathname.new(new_path)
74
+ end
75
+
76
+ def update(hash)
77
+ if hash.keys.first.is_a?(String)
78
+ update_from_key_paths(hash)
79
+ else
80
+ update_from_hash(hash)
81
+ end
82
+ self
83
+ end
84
+
85
+ def inspect
86
+ "#{super}:#{self.class.name}"
87
+ end
88
+
89
+ private
90
+
91
+ def update_from_hash(hash)
92
+ merger = proc { |_key, v1, v2|
93
+ Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2
94
+ }
95
+ merge!(hash, &merger)
96
+ end
97
+
98
+ def update_from_key_paths(key_paths)
99
+ key_paths.each { |key_path, value|
100
+ set(key_path, value)
101
+ }
102
+ end
103
+
104
+ def key_parts(key_path)
105
+ if key_path.is_a?(Symbol)
106
+ [key_path]
107
+ else
108
+ key_path.split('/').map { |key| key.intern }
109
+ end
110
+ end
111
+
112
+ def get_item(key_path)
113
+ parts = key_parts(key_path)
114
+ return nil if parts.empty?
115
+ item = self
116
+ parts.each { |key|
117
+ return nil if item.nil?
118
+ item = item[key]
119
+ }
120
+ item
121
+ end
122
+
123
+ def set_item(key_path, value)
124
+ item = self
125
+ parts = key_parts(key_path)
126
+ last_key = parts.pop
127
+ parts.each { |key|
128
+ item[key] ||= self.class.new
129
+ item = item[key]
130
+ }
131
+ item[last_key] = value
132
+ value
133
+ end
134
+
135
+ end