spinjector 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13754e7fa2165ee93579dd1d2064c9eb5e692ef67a2e2b7cd59f8a755b14a21b
4
- data.tar.gz: 21e6d78086b4ed644eaf628c1548fc6570f198d2ad3aaf224d51da41e4d065ba
3
+ metadata.gz: c73f5e26de7982019f85fa697d310590caf4750b75981e7bbcef7023a27e6c8c
4
+ data.tar.gz: 81933229a9142400ad0ae4ca2c9494064a384a73d9d88d091fda299749ddda5c
5
5
  SHA512:
6
- metadata.gz: f44c4b944a3a1859d5e2d9396bcc5a4ca4820d4d1b1f9633f1657b5b4f4430a60ab26bdedfa725bccba05c695a109d9e2d8e254c247a45b4d651639a88733463
7
- data.tar.gz: 45a06ffa00166fa35326be22ac1156f1930d42e5737906e6c0f3d9a34c904ff3d5490bf3ab3e5f3403d18e9ac6bfd2f9e9f589b6a62e1b85dae45e6bdb709952
6
+ metadata.gz: 2e766f518c4d1420ffaa5a28b4eedc69a9d4e94836bf0f5574cbc257efcb332f5797b77597681f04ee9824016498069a66eaebd3548f584a24befc4f5576fbc9
7
+ data.tar.gz: 61a8228e352c8c3f06770fcde3c5aeef9ffa3068b16986beb4cef7c91fa5e16e5c57bdd8ff2d566638fb914fe254c400da0f99f2f03ea4075aea74408bb022bc
data/Makefile ADDED
@@ -0,0 +1,11 @@
1
+ build:
2
+ gem build spinjector.gemspec
3
+
4
+ install: clean build
5
+ gem install spinjector-*.gem
6
+
7
+ publish: clean build
8
+ gem push spinjector-*.gem
9
+
10
+ clean:
11
+ rm -f spinjector-*.gem
data/README.md CHANGED
@@ -63,7 +63,7 @@ dependency_file: # optional.
63
63
  execution_position: # optional. [:before-compile | :after-compile | :before-headers | :after-headers].
64
64
  ```
65
65
 
66
- - If you use the `script_path option, create the script file
66
+ - If you use the `script_path option`, create the script file
67
67
  ```
68
68
  echo Hello World
69
69
  ```
@@ -77,3 +77,12 @@ spinjector [-c] <path-to-your-global-configuration-file>
77
77
  Enjoy your build phases
78
78
  ![Image of your build phases](/Examples/Images/build_phases.png)
79
79
  ![Image of hello world 2 build phase](/Examples/Images/hello_world_explicit.png)
80
+
81
+ ## How to contribute
82
+
83
+ 1. After all your changes are reviewed and merged
84
+ 2. Create a `release` branch
85
+ 3. Update the version in field `s.version` from file `spinjector.gemspec`
86
+ 4. Execute `make publish`
87
+
88
+ You may need to configure your account at step `4.` if you've never pushed any gem. You can find all the informations you need on [the official documentation](https://guides.rubygems.org/make-your-own-gem/#your-first-gem).
@@ -0,0 +1,9 @@
1
+
2
+ class Configuration
3
+
4
+ attr_reader :targets
5
+
6
+ def initialize(targets)
7
+ @targets = targets || []
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+
2
+ class Script
3
+
4
+ attr_reader :name, :source_code, :shell_path, :input_paths, :output_paths, :input_file_list_paths, :output_file_list_paths, :dependency_file, :execution_position, :show_env_vars_in_log
5
+
6
+ def initialize(
7
+ name,
8
+ source_code,
9
+ shell_path,
10
+ input_paths,
11
+ output_paths,
12
+ input_file_list_paths,
13
+ output_file_list_paths,
14
+ dependency_file,
15
+ execution_position,
16
+ show_env_vars_in_log
17
+ )
18
+ @name = name
19
+ @source_code = source_code
20
+ @shell_path = shell_path
21
+ @input_paths = input_paths
22
+ @output_paths = output_paths
23
+ @input_file_list_paths = input_file_list_paths
24
+ @output_file_list_paths = output_file_list_paths
25
+ @dependency_file = dependency_file
26
+ @execution_position = execution_position
27
+ @show_env_vars_in_log = show_env_vars_in_log
28
+ verify()
29
+ end
30
+
31
+ def verify
32
+ verify_execution_position()
33
+ end
34
+
35
+ def verify_execution_position
36
+ case execution_position
37
+ when :before_compile, :before_headers
38
+ true
39
+ when :after_compile, :after_headers
40
+ false
41
+ else
42
+ raise ArgumentError, "Unknown execution position `#{execution_position}`"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,10 @@
1
+
2
+ class Target
3
+
4
+ attr_reader :name, :scripts
5
+
6
+ def initialize(name, scripts)
7
+ @name = name
8
+ @scripts = scripts || []
9
+ end
10
+ end
@@ -0,0 +1,120 @@
1
+ require 'xcodeproj'
2
+ require_relative 'entity/configuration'
3
+ require_relative 'entity/script'
4
+ require_relative 'entity/target'
5
+
6
+ # @return [String] prefix used for all the build phase injected by this script
7
+ # [SPI] stands for Script Phase Injector
8
+ #
9
+ BUILD_PHASE_PREFIX = '[SPI] '.freeze
10
+
11
+ class ProjectService
12
+
13
+ # @param [Xcodeproj::Project] project
14
+ #
15
+ def initialize(project)
16
+ @project = project
17
+ end
18
+
19
+ # Remove all script phases prefixed by BUILD_PHASE_PREFIX from project
20
+ #
21
+ def remove_all_scripts
22
+ @project.targets.each do |target|
23
+ # Delete script phases no longer present in the target.
24
+ native_target_script_phases = target.shell_script_build_phases.select do |bp|
25
+ !bp.name.nil? && bp.name.start_with?(BUILD_PHASE_PREFIX)
26
+ end
27
+ native_target_script_phases.each do |script_phase|
28
+ target.build_phases.delete(script_phase)
29
+ end
30
+ end
31
+ end
32
+
33
+ # @param [Configuration] configuration containing all scripts to add in each target
34
+ #
35
+ def add_scripts_in_targets(configuration)
36
+ configuration.targets.each do |target|
37
+ xcode_target = app_target(target.name)
38
+ add_scripts_in_target(target.scripts, xcode_target)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # @param [String] target_name
45
+ # @return [Xcodeproj::Project::Object::PBXNativeTarget] the target named by target_name
46
+ #
47
+ def app_target(target_name)
48
+ target = @project.targets.find { |t| t.name == target_name }
49
+ raise "[Error] Invalid #{target_name} target." unless !target.nil?
50
+ return target
51
+ end
52
+
53
+ # @param [Array<Script>] scripts the script phases defined in configuration files
54
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] target to add the script phases
55
+ #
56
+ def add_scripts_in_target(scripts, target)
57
+ scripts.each do |script|
58
+ name_with_prefix = BUILD_PHASE_PREFIX + script.name
59
+ phase = target.new_shell_script_build_phase(name_with_prefix)
60
+ phase.shell_script = script.source_code
61
+ phase.shell_path = script.shell_path
62
+ phase.input_paths = script.input_paths
63
+ phase.output_paths = script.output_paths
64
+ phase.input_file_list_paths = script.input_file_list_paths
65
+ phase.output_file_list_paths = script.output_file_list_paths
66
+ phase.dependency_file = script.dependency_file
67
+ # At least with Xcode 10 `showEnvVarsInLog` is *NOT* set to any value even if it's checked and it only
68
+ # gets set to '0' if the user has explicitly disabled this.
69
+ if script.show_env_vars_in_log == '0'
70
+ phase.show_env_vars_in_log = script.show_env_vars_in_log
71
+ end
72
+ execution_position = script.execution_position
73
+ reorder_script_phase(target, phase, execution_position)
74
+ end
75
+ end
76
+
77
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] target where build phases should be reordered
78
+ # @param [Hash] script_phase to reorder
79
+ # @param [Symbol] execution_position could be :before_compile, :after_compile, :before_headers, :after_headers
80
+ #
81
+ def reorder_script_phase(target, script_phase, execution_position)
82
+ return if execution_position == :any || execution_position.to_s.empty?
83
+
84
+ # Find the point P where to add the script phase
85
+ target_phase_type = case execution_position
86
+ when :before_compile, :after_compile
87
+ Xcodeproj::Project::Object::PBXSourcesBuildPhase
88
+ when :before_headers, :after_headers
89
+ Xcodeproj::Project::Object::PBXHeadersBuildPhase
90
+ else
91
+ raise ArgumentError, "Unknown execution position `#{execution_position}`"
92
+ end
93
+
94
+ # Decide whether to add script_phase before or after point P
95
+ order_before = case execution_position
96
+ when :before_compile, :before_headers
97
+ true
98
+ when :after_compile, :after_headers
99
+ false
100
+ else
101
+ raise ArgumentError, "Unknown execution position `#{execution_position}`"
102
+ end
103
+
104
+ # Get the first build phase index of P
105
+ target_phase_index = target.build_phases.index do |bp|
106
+ bp.is_a?(target_phase_type)
107
+ end
108
+ return if target_phase_index.nil?
109
+
110
+ # Get the script phase we want to reorder index
111
+ script_phase_index = target.build_phases.index do |bp|
112
+ bp.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && !bp.name.nil? && bp.name == script_phase.name
113
+ end
114
+
115
+ # Move script phase to P if needed
116
+ if (order_before && script_phase_index > target_phase_index) || (!order_before && script_phase_index < target_phase_index)
117
+ target.build_phases.move_from(script_phase_index, target_phase_index)
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,36 @@
1
+ require_relative 'entity/script'
2
+
3
+ class ScriptMapper
4
+
5
+ def initialize(script_hash)
6
+ @script_hash = script_hash
7
+ verify_syntax
8
+ end
9
+
10
+ def map
11
+ script_code = @script_hash["script"] || load_script(@script_hash["script_path"])
12
+ Script.new(
13
+ @script_hash["name"],
14
+ script_code,
15
+ @script_hash["shell_path"] || '/bin/sh',
16
+ @script_hash["input_paths"] || [],
17
+ @script_hash["output_paths"] || [],
18
+ @script_hash["input_file_list_paths"] || [],
19
+ @script_hash["output_file_list_paths"] || [],
20
+ @script_hash["dependency_file"],
21
+ @script_hash["execution_position"] || :before_compile,
22
+ @script_hash["show_env_vars_in_log"]
23
+ )
24
+ end
25
+
26
+ def verify_syntax
27
+ raise "[Error] Invalid script description #{@script_hash}" unless @script_hash.is_a?(Hash)
28
+ raise "[Error] Script must have a name and an associated script" unless @script_hash.has_key?("name") && @script_hash.has_key?("script") || @script_hash.has_key?("script_path")
29
+ raise "[Error] Invalid name in script #{@script_hash}" unless !@script_hash["name"].nil?
30
+ end
31
+
32
+ def load_script(path)
33
+ raise "[Error] File #{path} does not exist" unless !path.nil? && File.exist?(path)
34
+ File.read(path)
35
+ end
36
+ end
@@ -0,0 +1,65 @@
1
+ require 'yaml'
2
+ require_relative 'entity/configuration'
3
+ require_relative 'entity/script'
4
+ require_relative 'entity/target'
5
+ require_relative 'script_mapper'
6
+
7
+ class YAMLParser
8
+
9
+ # The configuration to use in order to add scripts in your project
10
+ #
11
+ attr_reader :configuration
12
+
13
+ def initialize(yaml_file_path)
14
+ @configuration_description = load_yml_content(yaml_file_path)
15
+ @configuration = Configuration.new(targets)
16
+ end
17
+
18
+ private
19
+
20
+ def targets
21
+ if @configuration_description["targets"].nil?
22
+ puts "[Warning] There is no target in your configuration file."
23
+ return
24
+ end
25
+ @configuration_description["targets"].map do |target_name, script_entries|
26
+ if script_entries.nil?
27
+ puts "[Warning] There is no scripts in your configuration file under target #{target_name}"
28
+ return
29
+ end
30
+ scripts = script_entries.map do |entry|
31
+ get_script(entry)
32
+ end
33
+ Target.new(target_name, scripts)
34
+ end
35
+ end
36
+
37
+ def get_script(entry)
38
+ script =
39
+ if !@configuration_description["scripts"].nil? && !@configuration_description["scripts"][entry].nil?
40
+ get_script_by_name(entry)
41
+ elsif File.exist?(entry)
42
+ get_script_by_path(entry)
43
+ else
44
+ raise "[Error] Script #{entry} does not exist" unless !script.nil?
45
+ end
46
+ end
47
+
48
+ def get_script_by_name(name)
49
+ script_description = @configuration_description["scripts"][name]
50
+ ScriptMapper.new(script_description).map()
51
+ end
52
+
53
+ def get_script_by_path(path)
54
+ script_description = load_yml_content(path)
55
+ ScriptMapper.new(script_description).map()
56
+ end
57
+
58
+ # @param [String] configuration_path
59
+ # @return [Hash] the hash in the configuration file
60
+ #
61
+ def load_yml_content(configuration_path)
62
+ raise "[Error] YAML file #{configuration_path} not found." unless File.exist?(configuration_path)
63
+ YAML.load(File.read(configuration_path)) || {}
64
+ end
65
+ end
data/lib/spinjector.rb CHANGED
@@ -5,12 +5,8 @@
5
5
 
6
6
  require 'optparse'
7
7
  require 'xcodeproj'
8
- require 'yaml'
9
-
10
- # @return [String] prefix used for all the build phase injected by this script
11
- # [SPI] stands for Script Phase Injector
12
- #
13
- BUILD_PHASE_PREFIX = '[SPI] '.freeze
8
+ require_relative 'spinjector/project_service'
9
+ require_relative 'spinjector/yaml_parser'
14
10
 
15
11
  CONFIGURATION_FILE_PATH = 'Configuration/spinjector_configuration.yaml'.freeze
16
12
 
@@ -18,165 +14,21 @@ options = {}
18
14
  OptionParser.new do |opts|
19
15
  opts.banner = "Usage: spinjector [options]"
20
16
 
21
-
22
17
  opts.on("-cName", "--configuration-path=Name", "Inject scripts using configuration file at Name location. Default is ./#{CONFIGURATION_FILE_PATH}") do |config_path|
23
18
  options[:configuration_path] = config_path
24
19
  end
25
20
  end.parse!
26
21
 
27
- # @param [Xcodeproj::Project] project
28
- #
29
- def remove_all_spi_script_phases(project)
30
- project.targets.each do |target|
31
- # Delete script phases no longer present in the target.
32
- native_target_script_phases = target.shell_script_build_phases.select do |bp|
33
- !bp.name.nil? && bp.name.start_with?(BUILD_PHASE_PREFIX)
34
- end
35
- native_target_script_phases.each do |script_phase|
36
- target.build_phases.delete(script_phase)
37
- end
38
- end
39
- end
40
-
41
- # @param [Xcodeproj::Project] project
42
- #
43
- def inject_script_phases(project, configuration_file_path)
44
- configuration_file = load_yml_content(configuration_file_path)
45
- # Check if there are scripts in the global configuration file
46
- implicit_scripts = configuration_file["scripts"] || []
47
- configuration_file["targets"].each do |target_name, script_paths|
48
- script_phases = (script_paths || []).flat_map do |script_path|
49
- if !implicit_scripts.empty? and !implicit_scripts[script_path].nil?
50
- # Target uses script from the global configuration file
51
- script = implicit_scripts[script_path]
52
- else
53
- # Target uses script from a dedicated configuration file
54
- script = load_yml_content(script_path)
55
- end
56
- raise "[Error] Could not find script #{script_path}" unless !script.nil?
57
- script
58
- end
59
- warn "[Warning] No script phases found for #{target_name} target. You can add them in your configuration file at #{configuration_file_path}" unless !script_phases.empty?
60
- target = app_target(project, target_name)
61
- create_script_phases(script_phases, target)
62
- end
63
- end
64
-
65
- # @param [String] configuration_path
66
- # @return [Hash] the hash in the configuration file
67
- #
68
- def load_yml_content(configuration_path)
69
- raise "[Error] YAML file #{configuration_path} not found." unless File.exist?(configuration_path)
70
- YAML.load(File.read(configuration_path)) || {}
71
- end
72
-
73
- # @param [Xcodeproj::Project] project
74
- # @param [String] target_name
75
- # @return [Xcodeproj::Project::Object::PBXNativeTarget] the target named by target_name
76
- #
77
- def app_target(project, target_name)
78
- target = project.targets.find { |t| t.name == target_name }
79
- raise "[Error] Invalid #{target_name} target." unless !target.nil?
80
- return target
81
- end
82
-
83
- # @param [Array<Hash>] script_phases the script phases defined in configuration files
84
- # @param [Xcodeproj::Project::Object::PBXNativeTarget] target to add the script phases
85
- #
86
- def create_script_phases(script_phases, target)
87
- script_phases.each do |script_phase|
88
- name_with_prefix = BUILD_PHASE_PREFIX + script_phase["name"]
89
- phase = target.new_shell_script_build_phase(name_with_prefix)
90
- shell_script = get_script(script_phase)
91
- phase.shell_script = shell_script
92
- phase.shell_path = script_phase["shell_path"] || '/bin/sh'
93
- phase.input_paths = script_phase["input_paths"]
94
- phase.output_paths = script_phase["output_paths"]
95
- phase.input_file_list_paths = script_phase["input_file_list_paths"]
96
- phase.output_file_list_paths = script_phase["output_file_list_paths"]
97
- phase.dependency_file = script_phase["dependency_file"]
98
- # At least with Xcode 10 `showEnvVarsInLog` is *NOT* set to any value even if it's checked and it only
99
- # gets set to '0' if the user has explicitly disabled this.
100
- if (show_env_vars_in_log = script_phase.fetch("show_env_vars_in_log", '1')) == '0'
101
- phase.show_env_vars_in_log = show_env_vars_in_log
102
- end
103
-
104
- execution_position = script_phase["execution_position"] || :before_compile
105
- reorder_script_phase(target, phase, execution_position)
106
- end
107
- end
108
-
109
- # @param [Hash] script_phase the script phase defined in configuration files
110
- # @return [String] script to add in script phase
111
- #
112
- # If script is in a dedicated file, find the URL under <script_path>.
113
- # Otherwise, it may be written directly in the configuration file, find it under <script>.
114
- #
115
- def get_script(script_phase)
116
- if !script_phase["script"].nil? and !script_phase["script_path"].nil?
117
- raise "[Error] Script phase #{script_phase["name"]} contains 2 script sources. Please use one of :script_path or :script option"
118
- end
119
- if !script_phase["script_path"].nil?
120
- raise "[Error] File #{script_phase["script_path"]} does not exist" unless File.exist?(script_phase["script_path"])
121
- File.read(script_phase["script_path"])
122
- elsif !script_phase["script"].nil?
123
- script_phase["script"]
124
- else
125
- warn "[Warning] Script phase #{script_phase["name"]} contains no script"
126
- return ""
127
- end
128
- end
129
-
130
- # @param [Xcodeproj::Project::Object::PBXNativeTarget] target where build phases should be reordered
131
- # @param [Hash] script_phase to reorder
132
- # @param [Symbol] execution_position could be :before_compile, :after_compile, :before_headers, :after_headers
133
- #
134
- def reorder_script_phase(target, script_phase, execution_position)
135
- return if execution_position == :any || execution_position.to_s.empty?
136
-
137
- # Find the point P where to add the script phase
138
- target_phase_type = case execution_position
139
- when :before_compile, :after_compile
140
- Xcodeproj::Project::Object::PBXSourcesBuildPhase
141
- when :before_headers, :after_headers
142
- Xcodeproj::Project::Object::PBXHeadersBuildPhase
143
- else
144
- raise ArgumentError, "Unknown execution position `#{execution_position}`"
145
- end
146
-
147
- # Decide whether to add script_phase before or after point P
148
- order_before = case execution_position
149
- when :before_compile, :before_headers
150
- true
151
- when :after_compile, :after_headers
152
- false
153
- else
154
- raise ArgumentError, "Unknown execution position `#{execution_position}`"
155
- end
156
-
157
- # Get the first build phase index of P
158
- target_phase_index = target.build_phases.index do |bp|
159
- bp.is_a?(target_phase_type)
160
- end
161
- return if target_phase_index.nil?
162
-
163
- # Get the script phase we want to reorder index
164
- script_phase_index = target.build_phases.index do |bp|
165
- bp.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && !bp.name.nil? && bp.name == script_phase.name
166
- end
167
-
168
- # Move script phase to P if needed
169
- if (order_before && script_phase_index > target_phase_index) ||
170
- (!order_before && script_phase_index < target_phase_index)
171
- target.build_phases.move_from(script_phase_index, target_phase_index)
172
- end
173
- end
174
-
175
22
  project_path = Dir.glob("*.xcodeproj").first
176
23
  project = Xcodeproj::Project.open(project_path)
177
24
  raise "[Error] No xcodeproj found" unless !project.nil?
178
- remove_all_spi_script_phases(project)
25
+
179
26
  configuration_file_path = options[:configuration_path] || CONFIGURATION_FILE_PATH
180
- inject_script_phases(project, configuration_file_path)
27
+ configuration = YAMLParser.new(configuration_file_path).configuration
28
+
29
+ project_service = ProjectService.new(project)
30
+ project_service.remove_all_scripts()
31
+ project_service.add_scripts_in_targets(configuration)
32
+
181
33
  project.save()
182
34
  puts "Success."
data/spinjector.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'spinjector'
3
- s.version = '0.0.5'
3
+ s.version = '0.0.6'
4
4
  s.executables << 'spinjector'
5
5
  s.summary = "Inject script phases into your Xcode project"
6
6
  s.description = ""
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.email = 'guillaume.berthier@fabernovel.com'
9
9
  # use `git ls-files -coz -x *.gem` for development
10
10
  s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
11
- s.homepage = 'https://github.com/guillaumeberthier/spinjector'
11
+ s.homepage = 'https://github.com/faberNovel/spinjector'
12
12
  s.license = 'MIT'
13
13
 
14
14
  s.add_dependency 'optparse', '~> 0.1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spinjector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillaume Berthier, Fabernovel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-21 00:00:00.000000000 Z
11
+ date: 2022-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: optparse
@@ -60,8 +60,6 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - ".gitignore"
63
- - Examples/Configuration/hello_world_input
64
- - Examples/Configuration/hello_world_output
65
63
  - Examples/Configuration/helloworld.yaml
66
64
  - Examples/Configuration/helloworld_explicit_script.yaml
67
65
  - Examples/Configuration/helloworld_short.yaml
@@ -69,11 +67,18 @@ files:
69
67
  - Examples/Images/build_phases.png
70
68
  - Examples/Images/hello_world_explicit.png
71
69
  - Examples/Scripts/helloworld.sh
70
+ - Makefile
72
71
  - README.md
73
72
  - bin/spinjector
74
73
  - lib/spinjector.rb
74
+ - lib/spinjector/entity/configuration.rb
75
+ - lib/spinjector/entity/script.rb
76
+ - lib/spinjector/entity/target.rb
77
+ - lib/spinjector/project_service.rb
78
+ - lib/spinjector/script_mapper.rb
79
+ - lib/spinjector/yaml_parser.rb
75
80
  - spinjector.gemspec
76
- homepage: https://github.com/guillaumeberthier/spinjector
81
+ homepage: https://github.com/faberNovel/spinjector
77
82
  licenses:
78
83
  - MIT
79
84
  metadata: {}
File without changes
File without changes