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.
- checksums.yaml +4 -4
- data/.editorconfig +14 -0
- data/.gitignore +5 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/codeStyleSettings.xml +9 -0
- data/.idea/encodings.xml +6 -0
- data/.idea/inspectionProfiles/Project_Default.xml +8 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/runConfigurations/All_Features.xml +32 -0
- data/.idea/runConfigurations/test__skippy.xml +21 -0
- data/.idea/skippy.iml +83 -0
- data/.idea/vcs.xml +6 -0
- data/.vscode/launch.json +61 -0
- data/.vscode/settings.json +3 -2
- data/.vscode/tasks.json +16 -0
- data/Gemfile +5 -0
- data/Rakefile +4 -4
- data/app/boot.rb +1 -1
- data/app/commands/debug.rb +2 -1
- data/app/commands/lib.rb +46 -0
- data/app/commands/new.rb +4 -3
- data/app/commands/template.rb +3 -3
- data/app/resources/commands/example.rb +1 -1
- data/app/templates/standard/%ext_name%.rb.tt +1 -1
- data/app/templates/webdialog/{extension.rb.erb → %ext_name%.rb.tt} +1 -1
- data/app/templates/webdialog/{extension → %ext_name%}/html/dialog.html +0 -0
- data/app/templates/webdialog/{extension/main.rb.erb → %ext_name%/main.rb.tt} +0 -0
- data/bin/aruba +17 -0
- data/bin/cucumber +17 -0
- data/bin/htmldiff +17 -0
- data/bin/ldiff +17 -0
- data/cSpell.json +18 -0
- data/fixtures/my_lib/skippy.json +5 -0
- data/fixtures/my_lib/src/command.rb +4 -0
- data/fixtures/my_lib/src/geometry.rb +4 -0
- data/fixtures/my_lib/src/tool.rb +4 -0
- data/fixtures/my_project/skippy.json +8 -0
- data/fixtures/my_project/skippy/commands/example.rb +14 -0
- data/fixtures/my_project/src/hello_world.rb +47 -0
- data/fixtures/my_project/src/hello_world/extension.json +10 -0
- data/fixtures/my_project/src/hello_world/main.rb +21 -0
- data/lib/skippy.rb +7 -3
- data/lib/skippy/app.rb +7 -5
- data/lib/skippy/cli.rb +12 -12
- data/lib/skippy/config.rb +135 -0
- data/lib/skippy/config_accessors.rb +43 -0
- data/lib/skippy/error.rb +1 -1
- data/lib/skippy/helpers/file.rb +14 -0
- data/lib/skippy/lib_module.rb +47 -0
- data/lib/skippy/library.rb +57 -0
- data/lib/skippy/library_manager.rb +75 -0
- data/lib/skippy/module_manager.rb +103 -0
- data/lib/skippy/namespace.rb +7 -3
- data/lib/skippy/project.rb +55 -26
- data/lib/skippy/version.rb +1 -1
- data/skippy.gemspec +14 -12
- metadata +69 -8
- data/lib/skippy/skippy.rb +0 -9
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Skippy::ConfigAccessors
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def config_attr(*symbols, key: nil, type: nil)
|
9
|
+
config_attr_reader(*symbols, key: key, type: type)
|
10
|
+
config_attr_writer(*symbols, key: key, type: type)
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def config_attr_reader(*symbols, key: nil, type: nil)
|
15
|
+
self.class_eval {
|
16
|
+
symbols.each { |symbol|
|
17
|
+
raise TypeError unless symbol.is_a?(Symbol)
|
18
|
+
define_method(symbol) {
|
19
|
+
value = @config.get(key || symbol)
|
20
|
+
value = type.new(value) if type && !value.is_a?(type)
|
21
|
+
value
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def config_attr_writer(*symbols, key: nil, type: nil)
|
29
|
+
self.class_eval {
|
30
|
+
symbols.each { |symbol|
|
31
|
+
raise TypeError unless symbol.is_a?(Symbol)
|
32
|
+
symbol_set = "#{symbol}=".intern
|
33
|
+
define_method(symbol_set) { |value|
|
34
|
+
value = type.new(value) if type && !value.is_a?(type)
|
35
|
+
@config.set(key || symbol, value)
|
36
|
+
value
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/lib/skippy/error.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'skippy/library'
|
4
|
+
|
5
|
+
class Skippy::LibModule
|
6
|
+
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
class ModuleNotFoundError < Skippy::Error; end
|
10
|
+
|
11
|
+
# @param [String] path
|
12
|
+
def initialize(path)
|
13
|
+
@path = Pathname.new(path)
|
14
|
+
raise ModuleNotFoundError, @path.to_s unless @path.file?
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [String]
|
18
|
+
def basename
|
19
|
+
path.basename('.*').to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Skippy::Library]
|
23
|
+
def library
|
24
|
+
Skippy::Library.new(library_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [String]
|
28
|
+
def name
|
29
|
+
"#{library_name}/#{basename}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param [String]
|
33
|
+
def to_s
|
34
|
+
name
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def library_name
|
40
|
+
library_path.basename.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def library_path
|
44
|
+
path.parent.parent
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
require 'skippy/helpers/file'
|
5
|
+
require 'skippy/config'
|
6
|
+
require 'skippy/config_accessors'
|
7
|
+
require 'skippy/lib_module'
|
8
|
+
|
9
|
+
class Skippy::Library
|
10
|
+
|
11
|
+
extend Skippy::ConfigAccessors
|
12
|
+
|
13
|
+
include Skippy::Helpers::File
|
14
|
+
|
15
|
+
CONFIG_FILENAME = 'skippy.json'.freeze
|
16
|
+
|
17
|
+
attr_reader :path
|
18
|
+
|
19
|
+
config_attr_reader :title, key: :name # TODO(thomthom): Clean up this kludge.
|
20
|
+
config_attr_reader :version
|
21
|
+
|
22
|
+
class LibraryNotFoundError < Skippy::Error; end
|
23
|
+
|
24
|
+
def initialize(path)
|
25
|
+
@path = Pathname.new(path)
|
26
|
+
raise LibraryNotFoundError, @path.to_s unless @path.directory?
|
27
|
+
# noinspection RubyResolve
|
28
|
+
@config = Skippy::Config.load(config_file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def name
|
32
|
+
path.basename.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def modules
|
36
|
+
libs = modules_path.children(false).select { |file|
|
37
|
+
file.extname.downcase == '.rb'
|
38
|
+
}
|
39
|
+
libs.map! { |lib|
|
40
|
+
path = modules_path.join(lib)
|
41
|
+
Skippy::LibModule.new(path)
|
42
|
+
}
|
43
|
+
libs
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def config_file
|
49
|
+
path.join(CONFIG_FILENAME)
|
50
|
+
end
|
51
|
+
|
52
|
+
def modules_path
|
53
|
+
# TODO(thomthom): Make this configurable and default to 'lib'?
|
54
|
+
path.join('src')
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
require 'skippy/helpers/file'
|
5
|
+
require 'skippy/library'
|
6
|
+
require 'skippy/project'
|
7
|
+
|
8
|
+
class Skippy::LibraryManager
|
9
|
+
|
10
|
+
include Enumerable
|
11
|
+
include Skippy::Helpers::File
|
12
|
+
|
13
|
+
attr_reader :project
|
14
|
+
|
15
|
+
# @param [Skippy::Project] project
|
16
|
+
def initialize(project)
|
17
|
+
raise TypeError, 'expected a Project' unless project.is_a?(Skippy::Project)
|
18
|
+
@project = project
|
19
|
+
end
|
20
|
+
|
21
|
+
# @yield [Skippy::Library]
|
22
|
+
def each
|
23
|
+
directories(path).each { |lib_path|
|
24
|
+
yield Skippy::Library.new(lib_path)
|
25
|
+
}
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def empty?
|
30
|
+
to_a.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [String] module_name
|
34
|
+
# @return [Skippy::LibModule, nil]
|
35
|
+
def find_module(module_name)
|
36
|
+
library_name, module_name = module_name.split('/')
|
37
|
+
raise ArgumentError, 'expected a module path' if library_name.nil? || module_name.nil?
|
38
|
+
library = find { |lib| lib.name == library_name }
|
39
|
+
return nil if library.nil?
|
40
|
+
library.modules.find { |mod| mod.basename == module_name }
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param [Pathname, String] source
|
44
|
+
def install(source)
|
45
|
+
raise Skippy::Project::ProjectNotSavedError unless project.exist?
|
46
|
+
library = Skippy::Library.new(source)
|
47
|
+
|
48
|
+
target = path.join(library.name)
|
49
|
+
|
50
|
+
FileUtils.mkdir_p(path)
|
51
|
+
FileUtils.copy_entry(source, target)
|
52
|
+
|
53
|
+
project.config.push(:libraries, {
|
54
|
+
name: library.name,
|
55
|
+
version: library.version,
|
56
|
+
source: source
|
57
|
+
})
|
58
|
+
|
59
|
+
project.save
|
60
|
+
|
61
|
+
library
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Integer]
|
65
|
+
def length
|
66
|
+
to_a.length
|
67
|
+
end
|
68
|
+
alias :size :length
|
69
|
+
|
70
|
+
# @return [Pathname]
|
71
|
+
def path
|
72
|
+
project.path('.skippy/libs')
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
require 'skippy/helpers/file'
|
5
|
+
require 'skippy/lib_module'
|
6
|
+
require 'skippy/project'
|
7
|
+
|
8
|
+
class Skippy::ModuleManager
|
9
|
+
|
10
|
+
include Enumerable
|
11
|
+
include Skippy::Helpers::File
|
12
|
+
|
13
|
+
attr_reader :project
|
14
|
+
|
15
|
+
# @param [Skippy::Project] project
|
16
|
+
def initialize(project)
|
17
|
+
raise TypeError, 'expected a Project' unless project.is_a?(Skippy::Project)
|
18
|
+
@project = project
|
19
|
+
end
|
20
|
+
|
21
|
+
# @yield [Skippy::LibModule]
|
22
|
+
def each
|
23
|
+
directories(path).each { |library_path|
|
24
|
+
library_path.each_child { |module_file|
|
25
|
+
next unless module_file.file?
|
26
|
+
next unless module_file.extname == '.rb'
|
27
|
+
yield Skippy::LibModule.new(module_file)
|
28
|
+
}
|
29
|
+
}
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def empty?
|
34
|
+
to_a.empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [String] module_name
|
38
|
+
# @return [Skippy::LibModule, nil]
|
39
|
+
def find_module(module_name)
|
40
|
+
find { |lib_module| lib_module.name == module_name }
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param [Skippy::LibModule, String] lib_module
|
44
|
+
def installed?(lib_module)
|
45
|
+
module_name = lib_module.is_a?(Skippy::LibModule) ? lib_module.name : lib_module
|
46
|
+
project = Skippy::Project.current
|
47
|
+
project && project.config.get(:modules, []).any? { |mod| mod == module_name }
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param [String] module_name
|
51
|
+
# @return [Skippy::LibModule]
|
52
|
+
def use(module_name)
|
53
|
+
raise Skippy::Project::ProjectNotSavedError unless project.exist?
|
54
|
+
|
55
|
+
lib_module = project.libraries.find_module(module_name)
|
56
|
+
raise Skippy::LibModule::ModuleNotFoundError,
|
57
|
+
"module '#{module_name}' not found" if lib_module.nil?
|
58
|
+
|
59
|
+
source = lib_module.path
|
60
|
+
target = path.join(lib_module.library.name, lib_module.path.basename)
|
61
|
+
|
62
|
+
copy_module(source, target)
|
63
|
+
|
64
|
+
project.config.push(:modules, lib_module.to_s)
|
65
|
+
|
66
|
+
project.save
|
67
|
+
|
68
|
+
lib_module
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [Integer]
|
72
|
+
def length
|
73
|
+
to_a.length
|
74
|
+
end
|
75
|
+
alias :size :length
|
76
|
+
|
77
|
+
# @return [Pathname]
|
78
|
+
def path
|
79
|
+
project.path.join('src', project.namespace.to_underscore, 'vendor')
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# @param [Pathname, String] source
|
85
|
+
# @param [Pathname, String] target
|
86
|
+
def copy_module(source, target)
|
87
|
+
FileUtils.mkdir_p(target.parent)
|
88
|
+
content = File.read(source)
|
89
|
+
transform_module(content)
|
90
|
+
File.write(target, content)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Transform the module content with `SkippyLib` placeholder replaced with
|
94
|
+
# the project namespace.
|
95
|
+
#
|
96
|
+
# @param [String] content
|
97
|
+
# @return [String]
|
98
|
+
def transform_module(content)
|
99
|
+
content.gsub!('SkippyLib', project.namespace)
|
100
|
+
content
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
data/lib/skippy/namespace.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'skippy/error'
|
2
|
+
|
1
3
|
class Skippy::Namespace
|
2
4
|
|
3
5
|
def initialize(namespace)
|
@@ -13,12 +15,10 @@ class Skippy::Namespace
|
|
13
15
|
|
14
16
|
def open
|
15
17
|
@open ||= to_a.map { |part| "module #{part}" }.join("\n")
|
16
|
-
@open
|
17
18
|
end
|
18
19
|
|
19
20
|
def close
|
20
21
|
@close ||= to_a.reverse.map { |part| "end # module #{part}" }.join("\n")
|
21
|
-
@close
|
22
22
|
end
|
23
23
|
|
24
24
|
def to_a
|
@@ -33,6 +33,10 @@ class Skippy::Namespace
|
|
33
33
|
@namespace.dup
|
34
34
|
end
|
35
35
|
|
36
|
+
def to_str
|
37
|
+
to_s
|
38
|
+
end
|
39
|
+
|
36
40
|
def to_underscore
|
37
41
|
basename_words(basename).map { |word| word.downcase }.join('_')
|
38
42
|
end
|
@@ -52,4 +56,4 @@ class Skippy::Namespace
|
|
52
56
|
parts(namespace).all? { |part| /^[[:upper:]]/.match(part) }
|
53
57
|
end
|
54
58
|
|
55
|
-
end
|
59
|
+
end
|
data/lib/skippy/project.rb
CHANGED
@@ -1,14 +1,43 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'pathname'
|
3
3
|
|
4
|
+
require 'skippy/helpers/file'
|
5
|
+
require 'skippy/config'
|
6
|
+
require 'skippy/config_accessors'
|
7
|
+
require 'skippy/error'
|
8
|
+
require 'skippy/library_manager'
|
4
9
|
require 'skippy/namespace'
|
10
|
+
require 'skippy/module_manager'
|
5
11
|
|
6
12
|
class Skippy::Project
|
7
13
|
|
14
|
+
extend Skippy::ConfigAccessors
|
15
|
+
|
16
|
+
include Skippy::Helpers::File
|
17
|
+
|
8
18
|
PROJECT_FILENAME = 'skippy.json'.freeze
|
9
19
|
|
10
|
-
attr_reader :
|
11
|
-
|
20
|
+
attr_reader :config
|
21
|
+
attr_reader :libraries
|
22
|
+
attr_reader :modules
|
23
|
+
|
24
|
+
config_attr :author, :copyright, :description, :license, :name
|
25
|
+
config_attr :namespace, type: Skippy::Namespace
|
26
|
+
|
27
|
+
class ProjectNotFoundError < Skippy::Error; end
|
28
|
+
class ProjectNotSavedError < Skippy::Error; end
|
29
|
+
|
30
|
+
# @return [Skippy::Project, nil]
|
31
|
+
def self.current
|
32
|
+
Skippy::Project.new(Dir.pwd)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Skippy::Project]
|
36
|
+
def self.current_or_fail
|
37
|
+
project = self.current
|
38
|
+
raise ProjectNotFoundError unless project.exist?
|
39
|
+
project
|
40
|
+
end
|
12
41
|
|
13
42
|
# Initialize a project for the provided path. If the path is within a project
|
14
43
|
# path the base path of the project will be found. Otherwise it's assumed that
|
@@ -17,12 +46,10 @@ class Skippy::Project
|
|
17
46
|
# @param [Pathname, String] path
|
18
47
|
def initialize(path)
|
19
48
|
@path = find_project_path(path) || Pathname.new(path)
|
20
|
-
|
21
|
-
@
|
22
|
-
@
|
23
|
-
@
|
24
|
-
@copyright = "Copyright (c) #{Time.now.year}"
|
25
|
-
@license = 'None'
|
49
|
+
# noinspection RubyResolve
|
50
|
+
@config = Skippy::Config.load(filename, defaults)
|
51
|
+
@libraries = Skippy::LibraryManager.new(self)
|
52
|
+
@modules = Skippy::ModuleManager.new(self)
|
26
53
|
end
|
27
54
|
|
28
55
|
# @yield [filename]
|
@@ -36,42 +63,44 @@ class Skippy::Project
|
|
36
63
|
|
37
64
|
# Checks if a project exist on disk. If not it's just transient.
|
38
65
|
def exist?
|
39
|
-
|
66
|
+
filename.exist?
|
40
67
|
end
|
41
68
|
|
42
69
|
# Full path to the project's configuration file. This file may not exist.
|
43
|
-
# @return [
|
70
|
+
# @return [Pathname]
|
44
71
|
def filename
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
# @return [String]
|
49
|
-
def name
|
50
|
-
@name.empty? ? namespace.to_name : @name
|
72
|
+
path.join(PROJECT_FILENAME)
|
51
73
|
end
|
52
74
|
|
53
|
-
# @param [String]
|
54
|
-
|
55
|
-
|
75
|
+
# @param [Pathname, String] sub_path
|
76
|
+
# @return [Pathname]
|
77
|
+
def path(sub_path = '')
|
78
|
+
@path.join(sub_path)
|
56
79
|
end
|
57
80
|
|
58
81
|
# Commits the project to disk.
|
59
82
|
def save
|
60
|
-
|
83
|
+
@config.save_as(filename)
|
61
84
|
end
|
62
85
|
|
63
86
|
# @return [String]
|
64
87
|
def to_json
|
65
|
-
|
66
|
-
namespace: namespace,
|
67
|
-
name: name,
|
68
|
-
description: description
|
69
|
-
}
|
70
|
-
JSON.pretty_generate(project_config)
|
88
|
+
JSON.pretty_generate(@config)
|
71
89
|
end
|
72
90
|
|
73
91
|
private
|
74
92
|
|
93
|
+
def defaults
|
94
|
+
{
|
95
|
+
name: 'Untitled',
|
96
|
+
description: '',
|
97
|
+
namespace: Skippy::Namespace.new('Untitled'),
|
98
|
+
author: 'Unknown',
|
99
|
+
copyright: "Copyright (c) #{Time.now.year}",
|
100
|
+
license: 'None',
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
75
104
|
# Finds the root of a project based on any path within the project.
|
76
105
|
#
|
77
106
|
# @param [String] path
|