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