power_stencil 0.5.0 → 0.6.3

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/doc/builds.md +10 -1
  3. data/doc/entities.md +51 -42
  4. data/doc/plugins.md +59 -6
  5. data/doc/templates.md +1 -0
  6. data/etc/base_commands_definition.yml +14 -1
  7. data/etc/meta_templates/plugin_seed/etc/plugin_capabilities.yaml +2 -1
  8. data/etc/meta_templates/plugin_seed/psplugin_{entity}.gemspec +3 -1
  9. data/etc/templates/plugin_definition/etc/plugin_capabilities.yaml +2 -1
  10. data/etc/templates/plugin_definition/psplugin_{entity}.gemspec +3 -1
  11. data/lib/power_stencil/command_processors/build.rb +16 -3
  12. data/lib/power_stencil/command_processors/check.rb +12 -0
  13. data/lib/power_stencil/command_processors/create.rb +1 -1
  14. data/lib/power_stencil/command_processors/delete.rb +5 -5
  15. data/lib/power_stencil/command_processors/init.rb +2 -2
  16. data/lib/power_stencil/command_processors/plugin.rb +15 -5
  17. data/lib/power_stencil/command_processors/root.rb +1 -1
  18. data/lib/power_stencil/engine/build_handling.rb +1 -2
  19. data/lib/power_stencil/engine/directory_processor.rb +6 -1
  20. data/lib/power_stencil/engine/entities_definitions.rb +16 -7
  21. data/lib/power_stencil/engine/project_engine.rb +12 -5
  22. data/lib/power_stencil/initializer.rb +4 -7
  23. data/lib/power_stencil/plugins/base.rb +19 -9
  24. data/lib/power_stencil/plugins/capabilities.rb +10 -8
  25. data/lib/power_stencil/plugins/command_line.rb +1 -4
  26. data/lib/power_stencil/plugins/config.rb +1 -5
  27. data/lib/power_stencil/plugins/dsl.rb +24 -5
  28. data/lib/power_stencil/plugins/entity_definitions.rb +15 -0
  29. data/lib/power_stencil/plugins/gem.rb +14 -35
  30. data/lib/power_stencil/plugins/paths.rb +38 -0
  31. data/lib/power_stencil/plugins/require.rb +10 -16
  32. data/lib/power_stencil/plugins/templates.rb +1 -1
  33. data/lib/power_stencil/project/base.rb +12 -0
  34. data/lib/power_stencil/project/config.rb +3 -2
  35. data/lib/power_stencil/project/info.rb +14 -1
  36. data/lib/power_stencil/project/paths.rb +5 -25
  37. data/lib/power_stencil/project/plugins.rb +17 -22
  38. data/lib/power_stencil/system_entity_definitions/all.rb +1 -0
  39. data/lib/power_stencil/system_entity_definitions/entity_override.rb +1 -0
  40. data/lib/power_stencil/system_entity_definitions/entity_project_common.rb +1 -1
  41. data/lib/power_stencil/system_entity_definitions/project_entity.rb +1 -0
  42. data/lib/power_stencil/system_entity_definitions/simple_exec.rb +1 -1
  43. data/lib/power_stencil/system_entity_definitions/source_provider.rb +15 -0
  44. data/lib/power_stencil/utils/gem_utils.rb +22 -2
  45. data/lib/power_stencil/version.rb +1 -1
  46. data/power_stencil.gemspec +1 -1
  47. metadata +7 -5
@@ -12,7 +12,7 @@ module PowerStencil
12
12
  def execute
13
13
  analyse_extra_params.each do |search_criterion|
14
14
  begin
15
- puts_and_logs "Creating new entity '#{search_criterion.as_path}'"
15
+ puts_and_logs "Creating new entity '#{search_criterion.as_path}'", check_verbose: false
16
16
  entity_as_hash = {name: search_criterion.name}
17
17
  unless config[:property].nil?
18
18
  config[:property].each do |property_def|
@@ -12,21 +12,21 @@ module PowerStencil
12
12
  analyse_extra_params.each do |search_criterion|
13
13
  begin
14
14
  unless project.engine.entity *search_criterion.to_a, project.engine.root_universe
15
- puts "Skipping '#{search_criterion.as_path}'. Entity not found."
15
+ puts_and_logs "Skipping '#{search_criterion.as_path}'. Entity not found.", check_verbose: false
16
16
  next
17
17
  end
18
- puts_and_logs "Deleting entity '#{search_criterion.as_path}'"
18
+ puts_and_logs "Deleting entity '#{search_criterion.as_path}'", check_verbose: false
19
19
  if project.engine.delete_entity project.engine.root_universe,
20
20
  *search_criterion.to_a,
21
21
  delete_files: config[:'delete-files']
22
22
  msg = "Deleted '#{search_criterion.as_path}'"
23
23
  msg << ' and associated files.' if config[:'delete-files']
24
- puts msg
24
+ puts_and_logs msg, check_verbose: false
25
25
  else
26
- puts 'Cancelled by user input.'
26
+ puts_and_logs 'Cancelled by user input.', check_verbose: false
27
27
  end
28
28
  rescue => e
29
- puts "Failed to delete '#{search_criterion.as_path}' with message '#{e.message}'."
29
+ puts_and_logs "Failed to delete '#{search_criterion.as_path}' with message '#{e.message}'.", logs_as: :error, check_verbose: false
30
30
  logger.debug PowerStencil::Error.report_error(e)
31
31
  end
32
32
  end
@@ -15,9 +15,9 @@ module PowerStencil
15
15
  def execute
16
16
  setup_project_path
17
17
  log_startup_context
18
- puts_and_logs "Creating new project structure in '#{config[:'project-path']}'"
18
+ puts_and_logs "Creating new project structure in '#{config[:'project-path']}'", check_verbose: false
19
19
  PowerStencil::Project::Base.create_project_tree config[:'project-path']
20
- puts_and_logs 'Done.'
20
+ puts_and_logs 'Done.', check_verbose: false
21
21
  end
22
22
 
23
23
  private
@@ -8,6 +8,16 @@ module PowerStencil
8
8
  include PowerStencil::Project::Proxy
9
9
 
10
10
  def execute
11
+
12
+ if config[:install]
13
+ config[:project_plugins].each do |plugin_definition|
14
+ gem_name, gem_req = PowerStencil::Plugins::Base.plugin_definition_to_name_and_req plugin_definition
15
+ specs = PowerStencil::Plugins::Base.install_gem gem_name, gem_req
16
+ spec = specs.first
17
+ puts "Installed plugin '#{spec.name}' (version: #{spec.version})"
18
+ end
19
+ return
20
+ end
11
21
 
12
22
  if config[:list]
13
23
  if project.plugins.empty?
@@ -15,10 +25,10 @@ module PowerStencil
15
25
  else
16
26
  puts "#{project.plugins.size} plugin#{project.plugins.size == 1 ? '' : 's'} found to be used in this project."
17
27
  end
18
- project.plugins.each do |plugin_name, plugin_def|
19
- puts " - #{plugin_name} (in '#{plugin_def.entry_point_path}')"
28
+ project.plugins.each do |_, plugin|
29
+ puts " - #{plugin.name} (in '#{plugin.plugin_path}')"
20
30
  if config[:verbose]
21
- plugin_def.capabilities.each do |name, value|
31
+ plugin.capabilities.each do |name, value|
22
32
  puts " #{name}: #{value}"
23
33
  end
24
34
  end
@@ -33,8 +43,8 @@ module PowerStencil
33
43
  end
34
44
  config.command_line_layer.extra_parameters.each do |plugin_name|
35
45
  begin
36
- target_path = File.join project.project_plugin_path(plugin_name)
37
- project.create_plugin_tree plugin_name, target_path
46
+ target_path = File.join project.project_local_plugin_path(plugin_name)
47
+ project.create_new_local_plugin_tree plugin_name, target_path
38
48
  puts "Generated new plugin '#{plugin_name}'"
39
49
  rescue => e
40
50
  msg = "Could not create plugin '#{plugin_name}' because '#{e.message}'"
@@ -18,7 +18,7 @@ module PowerStencil
18
18
  unless config.command_line_layer.extra_parameters.empty?
19
19
  raise PowerStencil::Error, "Invalid command '#{config.command_line_layer.extra_parameters.first}'"
20
20
  end
21
- puts_and_logs 'No action specified. Exiting...'
21
+ puts_and_logs 'No action specified. Exiting...', check_verbose: false
22
22
  end
23
23
 
24
24
  end
@@ -39,8 +39,7 @@ module PowerStencil
39
39
  build_entity entity_to_build, build_entity_target_path
40
40
 
41
41
  entity_build_report << 'Ok'
42
- rescue => e
43
- logger.error "Failed building '#{entity_to_build.as_path}' because '#{e.message}' !"
42
+ rescue SyntaxError, StandardError => e
44
43
  entity_build_report << e.message
45
44
  if fail_on_error
46
45
  raise e
@@ -97,7 +97,12 @@ module PowerStencil
97
97
  raise PowerStencil::Error, "File '#{source}' is supposed to be rendered using '#{engine_name}', but seems not to be supported !"
98
98
  end
99
99
  context = running_context universe, main_entry_point: main_entry_point
100
- return send templating_engine_method_name, source, context
100
+ begin
101
+ return send templating_engine_method_name, source, context
102
+ rescue StandardError, SyntaxError => e
103
+ logger.puts_and_logs "Error rendering #{engine_name} template '#{source}'", logs_as: :error, check_verbose: false
104
+ raise e
105
+ end
101
106
  end
102
107
  end
103
108
  logger.warn "File '#{source}' was supposed to be processed but there is no template engine defined ! Applying simple copy."
@@ -7,7 +7,7 @@ module PowerStencil
7
7
 
8
8
  include PowerStencil::Utils::SecureRequire
9
9
 
10
- def require_definition_files(files_or_dirs)
10
+ def require_definition_files(files_or_dirs, source)
11
11
  required_files = []
12
12
  files_or_dirs.each do |file_or_dir|
13
13
  if File.directory? file_or_dir and File.readable? file_or_dir
@@ -21,21 +21,30 @@ module PowerStencil
21
21
  next
22
22
  end
23
23
  # This is a ruby library or there is something wrong
24
- securely_require file_or_dir
25
- # unless securely_require file_or_dir
26
- # logger.warn "While trying to load definition files, found that '#{file_or_dir}' has a problem. Ignored..."
27
- # end
24
+ securely_require_with_entity_class_detection file_or_dir, source
25
+
28
26
  end
29
- required_files.sort!.each {|file| securely_require file, fail_on_error: true}
27
+ required_files.sort!.each { |file| securely_require_with_entity_class_detection file, source }
30
28
  required_files
31
29
  end
32
30
 
33
31
  private
34
32
 
35
33
  def load_system_entities_definition
36
- require_definition_files [SYSTEM_ENTITY_DEFINITION_ENTRY_POINT]
34
+ require_definition_files [SYSTEM_ENTITY_DEFINITION_ENTRY_POINT], PowerStencil
37
35
  end
38
36
 
37
+ def securely_require_with_entity_class_detection(entity_definition_file_path, source)
38
+ before = PowerStencil::Engine::EntitiesHandling.all_types
39
+ securely_require entity_definition_file_path, fail_on_error: true
40
+ after = PowerStencil::Engine::EntitiesHandling.all_types
41
+ after.reject { |k, _| before.keys.include? k }
42
+ .each do |_, plugin_entity_class|
43
+ plugin_entity_class.instance_eval do
44
+ @entity_type_source_provider = source
45
+ end
46
+ end
47
+ end
39
48
  end
40
49
 
41
50
  end
@@ -17,11 +17,18 @@ module PowerStencil
17
17
  @project = project
18
18
  load_system_entities_definition
19
19
  load_plugins_entities_definition
20
- load_plugins_dsl_definition
21
20
  load_project_entities_definition
22
21
  load_entities
23
22
  end
24
23
 
24
+ def running_context(universe = root_universe, main_entry_point: nil)
25
+ context = dsl.new universe
26
+ apply_plugins_dsl_definition context
27
+ context.main_entry_point = main_entry_point
28
+ context.instance_eval do
29
+ binding
30
+ end
31
+ end
25
32
  protected
26
33
 
27
34
  def load_project_entities_definition
@@ -29,7 +36,7 @@ module PowerStencil
29
36
  if Dir.exist? dir and File.readable? dir
30
37
  logger.info 'Loading project specific entity definitions.'
31
38
  $LOAD_PATH << dir
32
- require_definition_files [dir]
39
+ require_definition_files [dir], project
33
40
  end
34
41
  end
35
42
 
@@ -44,13 +51,13 @@ module PowerStencil
44
51
 
45
52
  def load_plugins_entities_definition
46
53
  project.plugins.each do |_, plugin|
47
- plugin.require_plugin_entity_definitions if plugin.capabilities[:entity_definitions]
54
+ plugin.require_plugin_entity_definitions
48
55
  end
49
56
  end
50
57
 
51
- def load_plugins_dsl_definition
58
+ def apply_plugins_dsl_definition(context)
52
59
  project.plugins.each do |_, plugin|
53
- plugin.require_plugin_dsl if plugin.capabilities[:dsl]
60
+ plugin.apply_extra_dsl context
54
61
  end
55
62
  end
56
63
 
@@ -8,17 +8,15 @@ module PowerStencil
8
8
 
9
9
  include Climatic::Proxy
10
10
 
11
+ def name
12
+ 'PowerStencil core'
13
+ end
14
+
11
15
  def bootstrap(cmd_line_args = ARGV.dup)
12
16
  setup_climatic cmd_line_args
13
17
  logger.debug 'Starting PowerStencil initialization...'
14
18
  setup_system_processors
15
19
  setup_universe_compiler_logger
16
- # @project = try_to_load_project fail_on_error: false
17
- begin
18
- project.setup_templates_for_entities # unless project.nil?
19
- rescue => e
20
- logger.debug PowerStencil::Error.report_error e
21
- end
22
20
  logger.debug 'PowerStencil initialization complete'
23
21
  end
24
22
 
@@ -32,7 +30,6 @@ module PowerStencil
32
30
 
33
31
  def try_to_load_project(fail_on_error: true)
34
32
  PowerStencil::Project::Base.instantiate_from_config config
35
-
36
33
  end
37
34
 
38
35
  def setup_system_processors
@@ -1,3 +1,4 @@
1
+ require 'power_stencil/plugins/paths'
1
2
  require 'power_stencil/plugins/type'
2
3
  require 'power_stencil/plugins/config'
3
4
  require 'power_stencil/plugins/command_line'
@@ -19,6 +20,7 @@ module PowerStencil
19
20
 
20
21
  include Climatic::Proxy
21
22
  include PowerStencil::Plugins::Type
23
+ include PowerStencil::Plugins::Paths
22
24
  include PowerStencil::Plugins::Config
23
25
  include PowerStencil::Plugins::CommandLine
24
26
  include PowerStencil::Plugins::Require
@@ -26,28 +28,36 @@ module PowerStencil
26
28
  include PowerStencil::Plugins::EntityDefinitions
27
29
  include PowerStencil::Plugins::Templates
28
30
  include PowerStencil::Plugins::Build
31
+ include PowerStencil::Plugins::Dsl
29
32
 
30
- attr_reader :name, :version, :entry_point_path
33
+ attr_reader :name, :version, :entry_point_path, :gem_spec
31
34
 
32
- def initialize(name, project, type = :local)
35
+ def initialize(name, project, type: :local, gem_req: nil)
33
36
  @name = name
34
37
  @project = project
35
38
  @version = PowerStencil::Utils::SemanticVersion.new '0.0.0-not-specified'
36
39
  raise PowerStencil::Error, "Invalid plugin type (#{type}) for plugin '#{name}'" unless PLUGIN_TYPES.include? type
37
40
  @type = type
41
+ case type
42
+ when :gem
43
+ logger.debug "Plugin '#{name}' is provided as a Gem."
44
+ @gem_spec = PowerStencil::Plugins::Base.find_locally_installed_gem_spec name, gem_req
45
+ raise PowerStencil::Error, "Cannot find plugin '#{name}'. Try 'power_stencil plugin --install'" if gem_spec.nil?
46
+ raise PowerStencil::Error, "Invalid plugin '#{name}' ! Missing metadata 'plugin_name' in spec !" if gem_spec.metadata['plugin_name'].nil?
47
+ logger.debug "Plugin '#{name}' real name is '#{gem_spec.metadata['plugin_name']}'."
48
+ @name = gem_spec.metadata['plugin_name']
49
+ when :local
50
+ logger.debug "Plugin '#{name}' is provided locally by the project."
51
+ else
52
+ raise PowerStencil::Error, "Unsupported plugin type (#{type}) for plugin '#{name}' !"
53
+ end
54
+
38
55
  logger.debug "Loading plugin '#{name}'..."
39
56
  setup_plugin
40
57
  logger.info "Plugin '#{name}' successfully available"
41
58
  logger.debug "Plugin '#{name}' has following capabilities: #{capabilities.inspect}"
42
59
  end
43
60
 
44
- def path
45
- case type
46
- when :local
47
- project.project_plugin_path(name)
48
- end
49
- end
50
-
51
61
  def plugin_module
52
62
  Object.const_get plugin_definition[:plugin_module]
53
63
  end
@@ -9,10 +9,6 @@ module PowerStencil
9
9
 
10
10
  attr_reader :plugin_definition
11
11
 
12
- def plugin_capabilities_definition_file
13
- project.plugin_capabilities_definition_file self.name
14
- end
15
-
16
12
  def capabilities
17
13
  @capabilities ||= CAPABILITIES.dup.zip([false] * CAPABILITIES.size).to_h
18
14
  end
@@ -24,11 +20,17 @@ module PowerStencil
24
20
  unless File.exists? yaml_file and File.file? yaml_file and File.readable? yaml_file
25
21
  raise PowerStencil::Error, "Plugin '#{self.name}' has no definition file !"
26
22
  end
27
- @plugin_definition = yaml_file_to_hash yaml_file
28
- %i(processors entity_definitions templates build dsl).each do |capability|
29
- unless plugin_definition[capability].nil? or plugin_definition[capability].empty?
30
- capabilities[capability] = true
23
+ logger.debug "Loading plugin '#{self.name}' capabilities..."
24
+ begin
25
+ @plugin_definition = yaml_file_to_hash yaml_file
26
+ %i(processors entity_definitions templates build dsl).each do |capability|
27
+ unless plugin_definition[capability].nil? or plugin_definition[capability].empty?
28
+ capabilities[capability] = true
29
+ end
31
30
  end
31
+ rescue => e
32
+ logger.debug PowerStencil::Error.report_error(e)
33
+ raise PowerStencil::Error, "Invalid plugin capabilities file '#{yaml_file}' for plugin '#{self.name}'"
32
34
  end
33
35
 
34
36
  end
@@ -5,9 +5,6 @@ module PowerStencil
5
5
 
6
6
  attr_reader :plugin_command_line_modifier
7
7
 
8
- def plugin_commands_line_definition_file
9
- project.plugin_commands_line_definition_file self.name
10
- end
11
8
 
12
9
  def register_processors
13
10
  plugin_definition[:processors].each do |processors_name, processor|
@@ -20,7 +17,7 @@ module PowerStencil
20
17
  private
21
18
 
22
19
  def load_yaml_command_definition
23
- yaml_file = plugin_commands_line_definition_file
20
+ yaml_file = plugin_command_line_definition_file
24
21
  if File.exists? yaml_file and File.file? yaml_file and File.readable? yaml_file
25
22
  logger.info "Adding extra command line definition for '#{name}' plugin..."
26
23
  @plugin_command_line_modifier = project.yaml_file_to_hash yaml_file
@@ -3,17 +3,13 @@ module PowerStencil
3
3
 
4
4
  module Config
5
5
 
6
- def plugin_config_specific_file
7
- project.plugin_config_specific_file self.name
8
- end
9
-
10
6
  private
11
7
 
12
8
  def load_plugin_specific_config
13
9
  yaml_file = plugin_config_specific_file
14
10
  if File.exists? yaml_file and File.file? yaml_file and File.readable? yaml_file
15
11
  logger.info "Found plugin specific config in plugin '#{self.name}'. Attempting to load..."
16
- project.add_plugin_config self.name
12
+ project.add_plugin_config self
17
13
  capabilities[:config] = true
18
14
  end
19
15
  rescue => e
@@ -3,13 +3,32 @@ module PowerStencil
3
3
 
4
4
  module Dsl
5
5
 
6
- def require_plugin_dsl
7
- return unless capabilities[:dsl]
8
- logger.info "Requiring '#{self.name}' DSL addon definition..."
9
- plugin_definition[:dsl].each do |dsl_definition_file_path|
10
- securely_require dsl_definition_file_path, fail_on_error: true
6
+ def dsl_modules_names
7
+ return [] if plugin_definition[:dsl].nil?
8
+ case plugin_definition[:dsl]
9
+ when String
10
+ [plugin_definition[:dsl]]
11
+ when Array
12
+ plugin_definition[:dsl]
13
+ else
14
+ raise PowerStencil::Error, "Invalid DSL definition for plugin '#{self.name}' !"
11
15
  end
12
16
  end
17
+
18
+ def dsl_modules
19
+ dsl_modules_names.map { |dsl_module_name| Object.const_get dsl_module_name }
20
+ end
21
+
22
+ def apply_extra_dsl(dsl_base)
23
+ dsl_modules.each do |dsl_module|
24
+ logger.debug "Applying extra DSL '#{dsl_module.name}' to base DSL..."
25
+ dsl_base.extend dsl_module
26
+ end
27
+
28
+ end
29
+
30
+
31
+
13
32
  end
14
33
 
15
34
  end
@@ -6,9 +6,24 @@ module PowerStencil
6
6
  def require_plugin_entity_definitions
7
7
  return unless capabilities[:entity_definitions]
8
8
  logger.info "Requiring '#{self.name}' plugin entity definitions..."
9
+ securely_require_with_entity_class_detection
10
+ end
11
+
12
+
13
+ private
14
+
15
+ def securely_require_with_entity_class_detection
16
+ before = PowerStencil::Engine::EntitiesHandling.all_types
9
17
  plugin_definition[:entity_definitions].each do |entity_definition_file_path|
10
18
  securely_require entity_definition_file_path, fail_on_error: true
11
19
  end
20
+ after = PowerStencil::Engine::EntitiesHandling.all_types
21
+ after.reject { |k, _| before.keys.include? k }.each do |_, plugin_entity_class|
22
+ plugin = self
23
+ plugin_entity_class.instance_eval do
24
+ @entity_type_source_provider = plugin
25
+ end
26
+ end
12
27
  end
13
28
 
14
29
  end
@@ -5,50 +5,29 @@ module PowerStencil
5
5
 
6
6
  module Gem
7
7
 
8
+ include PowerStencil::Utils::GemUtils
9
+
8
10
  NO_DOC = %w(--no-document).freeze
9
11
 
10
- def gem_locally_installed?(plugin_name, plugin_requirements)
11
- get_spec(plugin_name, plugin_requirements).nil? ? false : true
12
- end
13
12
 
13
+ def is_available_gem?(gem_name)
14
14
 
15
- def install_gem(plugin_name, plugin_requirements)
16
- cmd = ::Gem::Commands::InstallCommand.new
17
- opts = [plugin_name]
18
- opts << plugin_requirements unless plugin_requirements.empty?
19
- opts.concat NO_DOC
20
- cmd.handle_options opts
21
- PowerStencil.logger.debug "Installing plugin '#{plugin_name}'..."
22
- cmd.execute
23
- PowerStencil.logger.debug "Plugin '#{plugin_name}' successfully installed."
24
- rescue ::Gem::SystemExitException => e
25
- PowerStencil.logger.warn PowerStencil::Error.report_error(e)
26
15
  end
27
16
 
17
+ def install_gem(plugin_name, plugin_requirements)
18
+ ::Gem.install plugin_name, plugin_requirements
19
+ end
28
20
 
29
21
 
30
- private
31
-
32
- def get_spec(plugin_name, plugin_requirements)
33
- candidates = ::Gem::Specification.find_all_by_name plugin_name
34
- if candidates.empty?
35
- PowerStencil.logger.debug "Could not find required plugin '#{plugin_name}'"
36
- return nil
37
- end
38
-
39
- req = if plugin_requirements.nil? or plugin_requirements.empty?
40
- ::Gem::Requirement::DefaultRequirement
41
- else
42
- ::Gem::Requirement.create plugin_requirements
43
- end
44
-
45
- selected = candidates.select {|candidate| req.satisfied_by? candidate.version}.sort {|a, b| a.version <=> b.version}
46
- if candidates.empty?
47
- PowerStencil.logger.debug "Could not find required plugin '#{plugin_name}'"
48
- return nil
49
- end
50
- selected.last
51
22
 
23
+ def find_locally_installed_gem_spec(gem_name, gem_requirements = ::Gem::Requirement.default)
24
+ # Normal method to find gem_spec doesn't work in the context of bundler !!
25
+ # candidates = ::Gem::Specification.find_all_by_name gem_name
26
+ candidates = find_gemspec_manually(gem_name)
27
+ .select {|candidate| gem_requirements.satisfied_by? candidate.version}
28
+ .sort {|a, b| a.version <=> b.version}
29
+ PowerStencil.logger.error "Could not find required plugin '#{gem_name}'" if candidates.empty?
30
+ candidates.last
52
31
  end
53
32
 
54
33
  end