vop 0.3.1 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/Gemfile +2 -1
  4. data/Gemfile.lock +34 -33
  5. data/README.md +184 -2
  6. data/bin/console +17 -0
  7. data/bin/setup +8 -0
  8. data/bin/vop.sh +6 -2
  9. data/exe/vop +3 -25
  10. data/lib/boot.rb +3 -0
  11. data/lib/core/meta/commands/new_command.rb +1 -0
  12. data/lib/core/meta/commands/new_plugin.rb +47 -0
  13. data/lib/core/meta/commands/search_gems_for_plugins.rb +38 -0
  14. data/lib/core/meta/commands/search_path.rb +6 -0
  15. data/lib/core/meta/commands/set.rb +12 -0
  16. data/lib/core/meta/commands/show.rb +6 -0
  17. data/lib/core/meta/commands/show_config.rb +9 -0
  18. data/lib/core/meta/commands/who_provides.rb +6 -0
  19. data/lib/core/meta/meta.plugin +1 -0
  20. data/lib/core/shell/commands/change_loglevel.rb +6 -0
  21. data/lib/{vop/plugins/core → core/shell}/commands/clear_context.rb +0 -0
  22. data/lib/core/shell/commands/edit.rb +12 -0
  23. data/lib/core/shell/commands/help.rb +49 -0
  24. data/lib/core/shell/commands/reset.rb +4 -0
  25. data/lib/{vop/plugins/core → core/shell}/commands/show_context.rb +0 -0
  26. data/lib/core/shell/commands/source.rb +21 -0
  27. data/lib/{vop/plugins/core/helpers/plugin_loader/plugin_syntax.rb → core/shell/shell.plugin} +0 -0
  28. data/lib/core/structure/commands/collect_contributions.rb +46 -0
  29. data/lib/core/structure/commands/disable_contributor.rb +16 -0
  30. data/lib/core/structure/commands/generate_entity_commands.rb +52 -0
  31. data/lib/core/structure/commands/generate_invalidation_commands.rb +26 -0
  32. data/lib/core/structure/commands/list_commands.rb +11 -0
  33. data/lib/core/structure/commands/list_contributors.rb +10 -0
  34. data/lib/core/structure/commands/list_entities.rb +3 -0
  35. data/lib/core/structure/commands/list_plugins.rb +3 -0
  36. data/lib/core/structure/commands/register_contributor.rb +14 -0
  37. data/lib/core/structure/structure.plugin +4 -0
  38. data/lib/vop/objects/chain.rb +25 -0
  39. data/lib/vop/objects/command.rb +86 -0
  40. data/lib/vop/objects/command_param.rb +39 -0
  41. data/lib/vop/objects/entities.rb +21 -0
  42. data/lib/vop/objects/entity.rb +75 -0
  43. data/lib/vop/objects/entity_definition.rb +33 -0
  44. data/lib/vop/objects/filter.rb +48 -0
  45. data/lib/vop/objects/plugin.rb +208 -0
  46. data/lib/vop/objects/request.rb +73 -0
  47. data/lib/vop/objects/response.rb +17 -0
  48. data/lib/vop/objects/thing_with_params.rb +17 -0
  49. data/lib/vop/{command_loader.rb → parts/command_loader.rb} +8 -12
  50. data/lib/vop/parts/dependency_resolver.rb +56 -0
  51. data/lib/vop/parts/entity_loader.rb +46 -0
  52. data/lib/vop/parts/executor.rb +155 -0
  53. data/lib/vop/parts/filter_loader.rb +41 -0
  54. data/lib/vop/parts/plugin_finder.rb +46 -0
  55. data/lib/vop/parts/plugin_loader.rb +72 -0
  56. data/lib/vop/shell/shell.rb +221 -0
  57. data/lib/vop/shell/shell_formatter.rb +110 -0
  58. data/lib/vop/shell/shell_input.rb +14 -0
  59. data/lib/vop/shell/shell_input_readline.rb +20 -0
  60. data/lib/vop/shell/shell_input_testable.rb +27 -0
  61. data/lib/vop/syntax/command_syntax.rb +90 -0
  62. data/lib/vop/syntax/entity_syntax.rb +35 -0
  63. data/lib/vop/syntax/filter_syntax.rb +11 -0
  64. data/lib/vop/syntax/plugin_syntax.rb +55 -0
  65. data/lib/vop/util/errors.rb +45 -0
  66. data/lib/vop/util/pluralizer.rb +26 -0
  67. data/lib/vop/util/worker.rb +24 -0
  68. data/lib/vop/version.rb +1 -1
  69. data/lib/vop/vop.rb +216 -0
  70. data/lib/vop.rb +16 -229
  71. data/vop.gemspec +18 -15
  72. metadata +95 -63
  73. data/bin/vop.rb +0 -28
  74. data/lib/vop/command.rb +0 -168
  75. data/lib/vop/entity.rb +0 -61
  76. data/lib/vop/loader.rb +0 -35
  77. data/lib/vop/plugin.rb +0 -141
  78. data/lib/vop/plugin_loader.rb +0 -88
  79. data/lib/vop/plugins/core/commands/collect_contributions.rb +0 -31
  80. data/lib/vop/plugins/core/commands/edit.rb +0 -12
  81. data/lib/vop/plugins/core/commands/help.rb +0 -38
  82. data/lib/vop/plugins/core/commands/identity.rb +0 -4
  83. data/lib/vop/plugins/core/commands/list_contributors.rb +0 -8
  84. data/lib/vop/plugins/core/commands/list_entities.rb +0 -3
  85. data/lib/vop/plugins/core/commands/pry.rb +0 -9
  86. data/lib/vop/plugins/core/commands/reset.rb +0 -5
  87. data/lib/vop/plugins/core/commands/source.rb +0 -5
  88. data/lib/vop/plugins/core/commands/system_call.rb +0 -5
  89. data/lib/vop/plugins/core/core.plugin +0 -4
  90. data/lib/vop/plugins/core/helpers/command_loader/command_syntax.rb +0 -45
  91. data/lib/vop/plugins/core/helpers/command_loader/contributions.rb +0 -28
  92. data/lib/vop/plugins/core/helpers/command_loader/entities.rb +0 -57
  93. data/lib/vop/plugins/core/helpers/helper.rb +0 -3
  94. data/lib/vop/plugins/meta/commands/add_search_path.rb +0 -6
  95. data/lib/vop/plugins/meta/commands/delete_plugin.rb +0 -13
  96. data/lib/vop/plugins/meta/commands/list_commands.rb +0 -17
  97. data/lib/vop/plugins/meta/commands/list_plugins.rb +0 -8
  98. data/lib/vop/plugins/meta/commands/new_command.rb +0 -14
  99. data/lib/vop/plugins/meta/commands/new_plugin.rb +0 -25
  100. data/lib/vop/plugins/meta/commands/show_search_path.rb +0 -3
  101. data/lib/vop/plugins/meta/commands/who_provides.rb +0 -5
  102. data/lib/vop/plugins/meta/meta.plugin +0 -1
  103. data/lib/vop/plugins/ssh/commands/scp.rb +0 -11
  104. data/lib/vop/plugins/ssh/commands/ssh.rb +0 -19
  105. data/lib/vop/plugins/ssh/ssh.plugin +0 -1
  106. data/lib/vop/shell/backend.rb +0 -28
  107. data/lib/vop/shell/base_shell.rb +0 -112
  108. data/lib/vop/shell/formatter.rb +0 -46
  109. data/lib/vop/shell/vop_shell_backend.rb +0 -257
  110. data/lib/vop/shell.rb +0 -52
@@ -0,0 +1,16 @@
1
+ param! "command_name", "command for which a contributor should be disabled"
2
+ param! "contributor", "name of the contributor to disable"
3
+
4
+ run do |plugin, command_name, contributor|
5
+ registry = plugin.state[:contributions] || {}
6
+ unless registry.has_key? command_name
7
+ raise "no contributors found for command #{command_name}"
8
+ end
9
+
10
+ contributors = registry[command_name]
11
+ unless contributors.include? contributor
12
+ raise "no contributor found with name #{contributor} for command #{command_name}"
13
+ end
14
+
15
+ contributors.delete(contributor)
16
+ end
@@ -0,0 +1,52 @@
1
+ description "each entity gets a command called <entities> automagically"
2
+
3
+ run do
4
+ result = []
5
+
6
+ @op.entities.each do |entity_name, definition|
7
+ list_command_name = definition.name.carefully_pluralize
8
+ $logger.debug "generating entity list command #{list_command_name} (#{definition.plugin.name})"
9
+
10
+ plugin = definition.plugin
11
+
12
+ list_command = Command.new(plugin, list_command_name)
13
+ # TODO list_command.read_only = true
14
+
15
+ if definition.on
16
+ list_command.add_param(definition.on.to_s, mandatory: true)
17
+ end
18
+
19
+ list_command.block = lambda do |params, request, context, plugin|
20
+ ex = Executor.new(@op)
21
+ block_param_names = definition.block.parameters.map { |x| x.last }
22
+ payload = ex.prepare_payload(request, context, block_param_names)
23
+
24
+ hash_array = definition.block.call(*payload)
25
+ if hash_array.nil?
26
+ $logger.warn "list block of entity '#{definition.name}' returned nil (?!)"
27
+ else
28
+ unless hash_array.is_a? Array
29
+ raise "unexpected data type : found #{hash_array.class}, expected Array"
30
+ end
31
+ entity_array = []
32
+ unless hash_array.empty?
33
+ first = hash_array.first
34
+ unless first.is_a? Hash
35
+ raise "entity '#{definition.name}' returned unexpected data type : found #{first.class}, expected Hash"
36
+ end
37
+ entity_array = hash_array.map do |row|
38
+ Entity.new(@op, definition.short_name, definition.key, row)
39
+ end
40
+ end
41
+
42
+ # wrap the resulting array of entities to add syntactic sugar
43
+ ::Vop::Entities.new(entity_array)
44
+ end
45
+ end
46
+ result << list_command
47
+ end
48
+
49
+ @op << result
50
+
51
+ result
52
+ end
@@ -0,0 +1,26 @@
1
+ description "all read-only commands get <command>! commands that invalidate automagically"
2
+
3
+ run do
4
+ count = 0
5
+ @op.commands.values.each do |command|
6
+ if command.read_only
7
+ invalidation_command_name = "#{command.short_name}!"
8
+ $logger.debug "generating invalidation command #{invalidation_command_name}"
9
+
10
+ invalidation_command = Command.new(command.plugin, invalidation_command_name)
11
+ invalidation_command.params = command.params
12
+
13
+ invalidation_command.block = lambda do |params|
14
+ @op.invalidate_cache(
15
+ "command" => command.short_name,
16
+ "raw_params" => params
17
+ )
18
+ @op.execute(command.short_name, params)
19
+ end
20
+
21
+ @op << invalidation_command
22
+ count += 1
23
+ end
24
+ end
25
+ count
26
+ end
@@ -0,0 +1,11 @@
1
+ param "plugin_filter", description: "name of a plugin by which commands should be filtered"
2
+
3
+ run do |plugin_filter|
4
+ result = @op.commands.values
5
+
6
+ unless plugin_filter.nil?
7
+ result.delete_if { |command| command.plugin.name != plugin_filter }
8
+ end
9
+
10
+ result.map { |command| command.name }.sort
11
+ end
@@ -0,0 +1,10 @@
1
+ param "command_name", description: "command for which contributors should be displayed"
2
+
3
+ run do |plugin, command_name|
4
+ registry = plugin.state[:contributions] || {}
5
+ if command_name
6
+ registry[command_name]
7
+ else
8
+ registry
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ run do |plugin|
2
+ @op.entities.keys
3
+ end
@@ -0,0 +1,3 @@
1
+ run do |plugin|
2
+ @op.plugins.map { |x| x.name }.sort
3
+ end
@@ -0,0 +1,14 @@
1
+ param! "command_name", description: "the target of the contribution"
2
+ param! "contributor", description: "the command that contributes"
3
+
4
+ run do |command_name, contributor, plugin|
5
+ # TODO verify that +command+ exists - cannot do it here because of
6
+ # 'machines.rails_machines' tries to contribute to unknown command 'machine'
7
+ # unless @op.commands.keys.include? command
8
+ # raise "'#{contributor}' tries to contribute to unknown command '#{command}'"
9
+ # end
10
+
11
+ # TODO initialize in init_hook (not here and in list_contributors)
12
+ registry = plugin.state[:contributions] ||= Hash.new { |h,k| h[k] = [] }
13
+ registry[command_name] << contributor
14
+ end
@@ -0,0 +1,4 @@
1
+ hook :loading_finished do
2
+ @op.generate_entity_commands
3
+ @op.generate_invalidation_commands
4
+ end
@@ -0,0 +1,25 @@
1
+ module Vop
2
+
3
+ class Chain
4
+
5
+ attr_reader :links
6
+
7
+ def initialize(op, links)
8
+ @op = op
9
+ @links = links
10
+ end
11
+
12
+ def next
13
+ @links.shift
14
+ end
15
+
16
+ def execute(request)
17
+ next_link = self.next
18
+ response = nil
19
+ response = next_link.execute(request) if next_link
20
+ response
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,86 @@
1
+ require_relative "command_param"
2
+
3
+ module Vop
4
+
5
+ class Command
6
+
7
+ attr_accessor :plugin
8
+ attr_accessor :name
9
+
10
+ attr_accessor :block
11
+ attr_accessor :params
12
+ attr_accessor :description
13
+
14
+ attr_accessor :show_options
15
+ attr_accessor :dont_register
16
+ attr_accessor :read_only
17
+ attr_accessor :allows_extra
18
+
19
+ def initialize(plugin, name)
20
+ @plugin = plugin
21
+ @name = name
22
+ @description = nil
23
+
24
+ @block = lambda { |params| $logger.warn "#{name} not yet implemented!" }
25
+
26
+ @params = []
27
+ @show_options = {}
28
+
29
+ @dont_register = false
30
+ @read_only = false
31
+ @allows_extra = false
32
+ end
33
+
34
+ def short_name
35
+ @name.split(".").last
36
+ end
37
+
38
+ def source
39
+ plugin.sources[:commands][name]
40
+ end
41
+
42
+ def param(name)
43
+ @params.select { |x| x.name == name }.first
44
+ end
45
+
46
+ def add_param(name, options = {})
47
+ @params << CommandParam.new(name, options)
48
+ end
49
+
50
+ def params_with(&filter)
51
+ params.select do |param|
52
+ filter.call(param)
53
+ end
54
+ end
55
+
56
+ def mandatory_params
57
+ params_with { |x| x.options[:mandatory] == true }
58
+ end
59
+
60
+ # The default param is the one used when a command is called with a single "scalar" param only, like
61
+ # @op.foo("zaphod")
62
+ # If a parameter is marked as default, it will be assigned the value "zaphod" in this case.
63
+ # If there is only a single param, it is the default param by default
64
+ # Also, if there is only one mandatory param, it is considered to be the default param
65
+ def default_param
66
+ if params.size == 1
67
+ params.first
68
+ else
69
+ result = params_with { |x| x.options[:default_param] == true }.first
70
+ if result.nil?
71
+ mandatory = mandatory_params
72
+ if mandatory_params.size == 1
73
+ result = mandatory.first
74
+ end
75
+ end
76
+ result
77
+ end
78
+ end
79
+
80
+ def execute(payload)
81
+ self.block.call(*payload)
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,39 @@
1
+ module Vop
2
+
3
+ class CommandParam
4
+
5
+ attr_reader :name, :options
6
+
7
+ def initialize(name, options = {})
8
+ @name = name
9
+
10
+ unless options.is_a? Hash
11
+ raise "[CommandParam] sanity check failed: unexpected options object class #{options.class}, expected Hash"
12
+ end
13
+
14
+ # auto-detect boolean parameters
15
+ if options.has_key? :default
16
+ if options[:default] == true || options[:default] == false
17
+ options[:boolean] = true
18
+ end
19
+ end
20
+
21
+ defaults = {
22
+ multi: false,
23
+ mandatory: false,
24
+ default_param: false
25
+ }
26
+ @options = defaults.merge(options)
27
+ end
28
+
29
+ # some params do not want to prefilled from the context
30
+ def wants_context
31
+ !(
32
+ options.has_key?(:use_context) &&
33
+ options[:use_context] == false
34
+ )
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,21 @@
1
+ module Vop
2
+
3
+ class Entities < Array
4
+
5
+ def [](key)
6
+ # if key.is_a? Numeric
7
+ # super(key)
8
+ # else
9
+ $logger.debug "accessing entity with key '#{key}'"
10
+ found = select { |x| x.id == key }.first
11
+ if found
12
+ found
13
+ else
14
+ raise "no element with key '#{key}'"
15
+ end
16
+ # end
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,75 @@
1
+ module Vop
2
+
3
+ class Entity
4
+
5
+ attr_reader :type, :data, :key
6
+
7
+ def initialize(op, type, key, data)
8
+ @op = op
9
+ @type = type
10
+ @key = key
11
+ @data = data
12
+
13
+ unless @data.has_key? @key
14
+ raise "key #{key} not found in data : #{data.keys.sort}"
15
+ end
16
+
17
+ make_methods_for_commands
18
+ make_method_for_id
19
+ end
20
+
21
+ def id
22
+ @data[@key]
23
+ end
24
+
25
+ def [](key)
26
+ @data[key]
27
+ end
28
+
29
+ def plugin
30
+ if @data.has_key? "plugin_name"
31
+ @op.plugin(@data["plugin_name"])
32
+ end
33
+ end
34
+
35
+ # all commands that have a parameter with the same name as the entity
36
+ # are considered eligible for this entity (TODO that's too broad, isn't it?)
37
+ def entity_commands
38
+ result = @op.commands.values.select do |command|
39
+ command.params.select do |param|
40
+ param.name == @type
41
+ end.count > 0
42
+ end
43
+ @command_count = result.count
44
+ result
45
+ end
46
+
47
+ def make_methods_for_commands
48
+ entity_commands.each do |command|
49
+ # TODO this is very similar to code in Vop.<<
50
+ self.class.send(:define_method, command.short_name) do |*args, &block|
51
+ $logger.debug "[#{@type}:#{id}] #{command.short_name} (#{args.pretty_inspect}, block? #{block_given?})"
52
+ ruby_args = args.length > 0 ? args[0] : {}
53
+ # TODO we might want to do this only if there's a block param defined
54
+ # TODO this does not work if *args comes with a scalar default param
55
+ if block
56
+ ruby_args["block"] = block
57
+ end
58
+ @op.execute(command.short_name, ruby_args, { @type.to_s => id })
59
+ end
60
+ end
61
+ end
62
+
63
+ def make_method_for_id
64
+ self.class.send(:define_method, @key) do |*args|
65
+ id
66
+ end
67
+ end
68
+
69
+ def to_s
70
+ "Vop::Entity (#{@type})"
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,33 @@
1
+ module Vop
2
+
3
+ class EntityDefinition
4
+
5
+ attr_reader :plugin, :name
6
+ attr_accessor :key
7
+ attr_accessor :block
8
+ attr_accessor :on
9
+ attr_accessor :show_options
10
+
11
+ def initialize(plugin, name)
12
+ @plugin = plugin
13
+ @name = name
14
+ @key = "name"
15
+ @data = {}
16
+
17
+ @block = lambda { |params| $logger.warn "entity #{name} does not have a run block" }
18
+
19
+ @on = nil
20
+ @show_options = {}
21
+ end
22
+
23
+ def short_name
24
+ @name.split(".").last
25
+ end
26
+
27
+ def source
28
+ plugin.sources[:entities][name]
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,48 @@
1
+ module Vop
2
+
3
+ class Filter
4
+
5
+ attr_reader :name, :plugin
6
+
7
+ attr_accessor :description
8
+ attr_accessor :block
9
+
10
+ def initialize(plugin, name)
11
+ @plugin = plugin
12
+ @name = name
13
+ end
14
+
15
+ def short_name
16
+ @name.split(".").last
17
+ end
18
+
19
+ def execute(request)
20
+ # this executor is just to prepare payload
21
+ ex = Executor.new(@plugin.op)
22
+ context = {}
23
+ block_param_names = self.block.parameters.map { |x| x.last }
24
+ payload = ex.prepare_payload(request, context, block_param_names)
25
+
26
+ response = nil
27
+ begin
28
+ response = self.block.call(*payload)
29
+ rescue InterruptChain => ic
30
+ response = ic.response
31
+ end
32
+
33
+ response
34
+ end
35
+
36
+ end
37
+
38
+ class InterruptChain < Exception
39
+
40
+ attr_reader :response
41
+
42
+ def initialize(response)
43
+ @response = response
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,208 @@
1
+ require "json"
2
+ require_relative "../parts/entity_loader"
3
+ require_relative "../parts/command_loader"
4
+ require_relative "../parts/filter_loader"
5
+ require_relative "thing_with_params"
6
+
7
+ module Vop
8
+
9
+ class Plugin < ThingWithParams
10
+
11
+ attr_reader :op
12
+ attr_reader :name
13
+ attr_accessor :description
14
+ attr_reader :options
15
+ attr_reader :commands
16
+
17
+ attr_reader :sources
18
+ attr_reader :state
19
+ attr_reader :config
20
+ attr_accessor :dependencies
21
+
22
+ def initialize(op, plugin_name, plugin_path, options = {})
23
+ super()
24
+
25
+ @op = op
26
+ @name = plugin_name
27
+ @path = plugin_path
28
+
29
+ defaults = {
30
+ auto_load: true
31
+ }
32
+ @options = defaults.merge(options)
33
+
34
+ @description = nil
35
+
36
+ @state = {}
37
+
38
+ @config_file_name = File.join(op.plugin_config_path, plugin_name + ".json")
39
+ @config = {}
40
+
41
+ @dependencies = []
42
+
43
+ @hooks = {}
44
+ end
45
+
46
+ def to_s
47
+ "Vop::Plugin #{name}"
48
+ end
49
+
50
+ def init
51
+ $logger.debug "plugin init : #{@name}"
52
+
53
+ @sources = Hash.new { |h, k| h[k] = {} }
54
+
55
+ @config = {}
56
+
57
+ # call_hook :preload ?
58
+ load_helpers
59
+ load_default_config
60
+ load_config
61
+
62
+ # TODO proceed only if auto_load
63
+ call_hook :init
64
+ load_entities
65
+ load_commands
66
+ load_filters
67
+
68
+ #@op.call_global_hook :plugin_loaded, self
69
+ end
70
+
71
+ def plugin_dir(name)
72
+ File.join(@path, name.to_s)
73
+ end
74
+
75
+ def load_default_config
76
+ params.each do |param|
77
+ if param.options.has_key?(:default)
78
+ @config[param.name] = param.options[:default]
79
+ end
80
+ end
81
+ end
82
+
83
+ def load_config
84
+ $logger.debug "looking for config at #{@config_file_name}"
85
+ if File.exists? @config_file_name
86
+ raw = nil
87
+ begin
88
+ raw = IO.read(@config_file_name)
89
+ config_from_file = JSON.parse(raw)
90
+ @config.merge! config_from_file
91
+ $logger.debug "plugin config loaded from #{@config_file_name}"
92
+ rescue => e
93
+ $logger.error "could not read JSON config from #{@config_file_name} (#{e.message}), ignoring:\n#{raw}"
94
+ end
95
+ end
96
+ end
97
+
98
+ def write_config
99
+ $logger.info "writing config into #{@op.plugin_config_path}"
100
+ unless Dir.exists?(@op.plugin_config_path)
101
+ FileUtils.mkdir_p @op.plugin_config_path
102
+ end
103
+ File.open(@config_file_name, "w") do |file|
104
+ file.write @config.to_json()
105
+ end
106
+ end
107
+
108
+ def load_code_from_dir(type_name)
109
+ dir = plugin_dir(type_name)
110
+
111
+ if File.exists?(dir)
112
+ Dir.glob(File.join(dir, "*.rb")).each do |file_name|
113
+ name_from_file = /#{dir}\/(.+).rb$/.match(file_name).captures.first
114
+ full_name = [@name, name_from_file].join(".")
115
+ $logger.debug(" #{type_name} << #{full_name}")
116
+
117
+ @sources[type_name][full_name] = {
118
+ :file_name => file_name,
119
+ :code => File.read(file_name)
120
+ }
121
+ end
122
+ end
123
+ end
124
+
125
+ def load_entities
126
+ loader = EntityLoader.new(self)
127
+
128
+ load_code_from_dir :entities
129
+ @entities = loader.read_sources @sources[:entities]
130
+ @op << @entities unless @entities.empty?
131
+ end
132
+
133
+ def load_commands
134
+ loader = CommandLoader.new(self)
135
+
136
+ load_code_from_dir :commands
137
+ @commands = loader.read_sources @sources[:commands]
138
+ @op << @commands unless @commands.empty?
139
+ end
140
+
141
+ def load_filters
142
+ loader = FilterLoader.new(self)
143
+
144
+ load_code_from_dir :filters
145
+ @filters = loader.read_sources @sources[:filters]
146
+ @op << @filters unless @filters.empty?
147
+ end
148
+
149
+ def load_helpers
150
+ #load_code_from_dir :helpers
151
+ load_code_from_dir("helpers") # TODO unify (symbol vs. string) with load_commands above
152
+ end
153
+
154
+ def inject_helpers(target, sub_type_name = nil)
155
+ type_name = 'helpers'
156
+
157
+ plugins_to_load_helpers_from = [ self ]
158
+
159
+ self.dependencies.each do |name|
160
+ other = @op.plugin(name)
161
+ raise "can not resolve plugin dependency #{name}" unless other
162
+ plugins_to_load_helpers_from << other
163
+ end
164
+
165
+ plugins_to_load_helpers_from.each do |other_plugin|
166
+ helper_sources = other_plugin.sources[type_name]
167
+
168
+ next if helper_sources.size == 0
169
+
170
+ helper_module = Module.new()
171
+
172
+ helper_sources.each do |name, helper|
173
+ begin
174
+ helper_module.class_eval helper[:code]
175
+ rescue Exception => e
176
+ $stderr.puts("could not read helper #{name} : #{e.message}")
177
+ raise e
178
+ end
179
+ end
180
+
181
+ target.extend helper_module
182
+ end
183
+ end
184
+
185
+ def hook(name, &block)
186
+ @hooks[name.to_sym] = block
187
+ end
188
+
189
+ def call_hook(name, *args)
190
+ result = nil
191
+ if @hooks.has_key? name
192
+ result = @hooks[name].call(self, *args)
193
+ end
194
+ result
195
+ end
196
+
197
+ def template_path(name)
198
+ name += ".erb" unless name.end_with? ".erb"
199
+ File.join(plugin_dir(:templates), name)
200
+ end
201
+
202
+ def template(name)
203
+ @op.read_template(template_path(name))
204
+ end
205
+
206
+ end
207
+
208
+ end