nucleon 0.1.19 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +1 -0
  4. data/TODO.rdoc +0 -3
  5. data/VERSION +1 -1
  6. data/bin/nucleon +19 -0
  7. data/lib/core/config.rb +11 -7
  8. data/lib/core/environment.rb +338 -0
  9. data/lib/core/facade.rb +150 -98
  10. data/lib/core/manager.rb +160 -249
  11. data/lib/core/mixin/action/project.rb +2 -2
  12. data/lib/core/mixin/macro/plugin_interface.rb +11 -11
  13. data/lib/core/plugin/action.rb +277 -24
  14. data/lib/core/plugin/base.rb +22 -14
  15. data/lib/core/plugin/command.rb +1 -1
  16. data/lib/core/plugin/event.rb +3 -3
  17. data/lib/core/plugin/extension.rb +1 -1
  18. data/lib/core/plugin/project.rb +15 -15
  19. data/lib/core/plugin/template.rb +1 -1
  20. data/lib/core/plugin/translator.rb +1 -1
  21. data/lib/core/util/cache.rb +1 -1
  22. data/lib/core/util/cli.rb +32 -3
  23. data/lib/core/util/console.rb +30 -10
  24. data/lib/core/util/data.rb +11 -3
  25. data/lib/core/util/logger.rb +1 -1
  26. data/lib/core/util/shell.rb +6 -3
  27. data/lib/core/util/ssh.rb +148 -24
  28. data/lib/nucleon/action/extract.rb +11 -4
  29. data/lib/nucleon/action/{add.rb → project/add.rb} +13 -4
  30. data/lib/nucleon/action/{create.rb → project/create.rb} +12 -3
  31. data/lib/nucleon/action/{remove.rb → project/remove.rb} +11 -2
  32. data/lib/nucleon/action/{save.rb → project/save.rb} +11 -2
  33. data/lib/nucleon/action/{update.rb → project/update.rb} +11 -2
  34. data/lib/nucleon/command/bash.rb +1 -1
  35. data/lib/nucleon/event/regex.rb +1 -1
  36. data/lib/nucleon/project/git.rb +3 -3
  37. data/lib/nucleon/template/{json.rb → JSON.rb} +1 -1
  38. data/lib/nucleon/template/{yaml.rb → YAML.rb} +1 -1
  39. data/lib/nucleon/template/wrapper.rb +1 -1
  40. data/lib/nucleon/translator/{json.rb → JSON.rb} +1 -1
  41. data/lib/nucleon/translator/{yaml.rb → YAML.rb} +1 -1
  42. data/lib/nucleon_base.rb +26 -15
  43. data/locales/en.yml +69 -44
  44. data/nucleon.gemspec +129 -11
  45. data/rdoc/site/0.1.19/ARCHITECTURE_rdoc.html +634 -0
  46. data/rdoc/site/0.1.19/Hash.html +347 -0
  47. data/rdoc/site/0.1.19/Kernel.html +413 -0
  48. data/rdoc/site/0.1.19/Nucleon.html +570 -0
  49. data/rdoc/site/0.1.19/Nucleon/Action.html +280 -0
  50. data/rdoc/site/0.1.19/Nucleon/Action/Add.html +458 -0
  51. data/rdoc/site/0.1.19/Nucleon/Action/Create.html +415 -0
  52. data/rdoc/site/0.1.19/Nucleon/Action/Extract.html +413 -0
  53. data/rdoc/site/0.1.19/Nucleon/Action/Remove.html +461 -0
  54. data/rdoc/site/0.1.19/Nucleon/Action/Save.html +434 -0
  55. data/rdoc/site/0.1.19/Nucleon/Action/Update.html +381 -0
  56. data/rdoc/site/0.1.19/Nucleon/Codes.html +563 -0
  57. data/rdoc/site/0.1.19/Nucleon/Command.html +275 -0
  58. data/rdoc/site/0.1.19/Nucleon/Command/Bash.html +544 -0
  59. data/rdoc/site/0.1.19/Nucleon/Config.html +1623 -0
  60. data/rdoc/site/0.1.19/Nucleon/Config/Collection.html +509 -0
  61. data/rdoc/site/0.1.19/Nucleon/Config/Options.html +489 -0
  62. data/rdoc/site/0.1.19/Nucleon/Core.html +635 -0
  63. data/rdoc/site/0.1.19/Nucleon/Errors.html +275 -0
  64. data/rdoc/site/0.1.19/Nucleon/Errors/BatchError.html +281 -0
  65. data/rdoc/site/0.1.19/Nucleon/Errors/NucleonError.html +657 -0
  66. data/rdoc/site/0.1.19/Nucleon/Errors/SSHUnavailable.html +281 -0
  67. data/rdoc/site/0.1.19/Nucleon/Event.html +275 -0
  68. data/rdoc/site/0.1.19/Nucleon/Event/Regex.html +467 -0
  69. data/rdoc/site/0.1.19/Nucleon/Facade.html +2336 -0
  70. data/rdoc/site/0.1.19/Nucleon/Gems.html +635 -0
  71. data/rdoc/site/0.1.19/Nucleon/Manager.html +1828 -0
  72. data/rdoc/site/0.1.19/Nucleon/Mixin.html +284 -0
  73. data/rdoc/site/0.1.19/Nucleon/Mixin/Action.html +277 -0
  74. data/rdoc/site/0.1.19/Nucleon/Mixin/Action/Commit.html +381 -0
  75. data/rdoc/site/0.1.19/Nucleon/Mixin/Action/Project.html +395 -0
  76. data/rdoc/site/0.1.19/Nucleon/Mixin/Action/Push.html +371 -0
  77. data/rdoc/site/0.1.19/Nucleon/Mixin/Colors.html +545 -0
  78. data/rdoc/site/0.1.19/Nucleon/Mixin/ConfigCollection.html +481 -0
  79. data/rdoc/site/0.1.19/Nucleon/Mixin/ConfigOptions.html +449 -0
  80. data/rdoc/site/0.1.19/Nucleon/Mixin/Macro.html +276 -0
  81. data/rdoc/site/0.1.19/Nucleon/Mixin/Macro/ObjectInterface.html +695 -0
  82. data/rdoc/site/0.1.19/Nucleon/Mixin/Macro/PluginInterface.html +682 -0
  83. data/rdoc/site/0.1.19/Nucleon/Mixin/Settings.html +481 -0
  84. data/rdoc/site/0.1.19/Nucleon/Mixin/SubConfig.html +887 -0
  85. data/rdoc/site/0.1.19/Nucleon/Parallel.html +325 -0
  86. data/rdoc/site/0.1.19/Nucleon/Parallel/ClassMethods.html +325 -0
  87. data/rdoc/site/0.1.19/Nucleon/Parallel/InstanceMethods.html +334 -0
  88. data/rdoc/site/0.1.19/Nucleon/Plugin.html +282 -0
  89. data/rdoc/site/0.1.19/Nucleon/Plugin/Action.html +1368 -0
  90. data/rdoc/site/0.1.19/Nucleon/Plugin/Action/Option.html +459 -0
  91. data/rdoc/site/0.1.19/Nucleon/Plugin/Base.html +1737 -0
  92. data/rdoc/site/0.1.19/Nucleon/Plugin/Command.html +721 -0
  93. data/rdoc/site/0.1.19/Nucleon/Plugin/Event.html +442 -0
  94. data/rdoc/site/0.1.19/Nucleon/Plugin/Extension.html +281 -0
  95. data/rdoc/site/0.1.19/Nucleon/Plugin/Project.html +2864 -0
  96. data/rdoc/site/0.1.19/Nucleon/Plugin/Template.html +476 -0
  97. data/rdoc/site/0.1.19/Nucleon/Plugin/Translator.html +371 -0
  98. data/rdoc/site/0.1.19/Nucleon/Project.html +276 -0
  99. data/rdoc/site/0.1.19/Nucleon/Project/Git.html +1801 -0
  100. data/rdoc/site/0.1.19/Nucleon/Project/Github.html +549 -0
  101. data/rdoc/site/0.1.19/Nucleon/Template.html +277 -0
  102. data/rdoc/site/0.1.19/Nucleon/Template/Json.html +329 -0
  103. data/rdoc/site/0.1.19/Nucleon/Template/Wrapper.html +329 -0
  104. data/rdoc/site/0.1.19/Nucleon/Template/Yaml.html +329 -0
  105. data/rdoc/site/0.1.19/Nucleon/Translator.html +276 -0
  106. data/rdoc/site/0.1.19/Nucleon/Translator/Json.html +366 -0
  107. data/rdoc/site/0.1.19/Nucleon/Translator/Yaml.html +366 -0
  108. data/rdoc/site/0.1.19/Nucleon/Util.html +285 -0
  109. data/rdoc/site/0.1.19/Nucleon/Util/CLI.html +388 -0
  110. data/rdoc/site/0.1.19/Nucleon/Util/CLI/Parser.html +1183 -0
  111. data/rdoc/site/0.1.19/Nucleon/Util/Cache.html +780 -0
  112. data/rdoc/site/0.1.19/Nucleon/Util/Console.html +1294 -0
  113. data/rdoc/site/0.1.19/Nucleon/Util/Data.html +1399 -0
  114. data/rdoc/site/0.1.19/Nucleon/Util/Disk.html +522 -0
  115. data/rdoc/site/0.1.19/Nucleon/Util/Git.html +361 -0
  116. data/rdoc/site/0.1.19/Nucleon/Util/Liquid.html +365 -0
  117. data/rdoc/site/0.1.19/Nucleon/Util/Logger.html +806 -0
  118. data/rdoc/site/0.1.19/Nucleon/Util/Package.html +558 -0
  119. data/rdoc/site/0.1.19/Nucleon/Util/SSH.html +910 -0
  120. data/rdoc/site/0.1.19/Nucleon/Util/SSH/Keypair.html +453 -0
  121. data/rdoc/site/0.1.19/Nucleon/Util/Shell.html +686 -0
  122. data/rdoc/site/0.1.19/Nucleon/Util/Shell/Result.html +497 -0
  123. data/rdoc/site/0.1.19/README_rdoc.html +312 -0
  124. data/rdoc/site/0.1.19/TODO_rdoc.html +267 -0
  125. data/rdoc/site/0.1.19/created.rid +60 -0
  126. data/rdoc/site/0.1.19/images/add.png +0 -0
  127. data/rdoc/site/0.1.19/images/brick.png +0 -0
  128. data/rdoc/site/0.1.19/images/brick_link.png +0 -0
  129. data/rdoc/site/0.1.19/images/bug.png +0 -0
  130. data/rdoc/site/0.1.19/images/bullet_black.png +0 -0
  131. data/rdoc/site/0.1.19/images/bullet_toggle_minus.png +0 -0
  132. data/rdoc/site/0.1.19/images/bullet_toggle_plus.png +0 -0
  133. data/rdoc/site/0.1.19/images/date.png +0 -0
  134. data/rdoc/site/0.1.19/images/delete.png +0 -0
  135. data/rdoc/site/0.1.19/images/find.png +0 -0
  136. data/rdoc/site/0.1.19/images/loadingAnimation.gif +0 -0
  137. data/rdoc/site/0.1.19/images/macFFBgHack.png +0 -0
  138. data/rdoc/site/0.1.19/images/package.png +0 -0
  139. data/rdoc/site/0.1.19/images/page_green.png +0 -0
  140. data/rdoc/site/0.1.19/images/page_white_text.png +0 -0
  141. data/rdoc/site/0.1.19/images/page_white_width.png +0 -0
  142. data/rdoc/site/0.1.19/images/plugin.png +0 -0
  143. data/rdoc/site/0.1.19/images/ruby.png +0 -0
  144. data/rdoc/site/0.1.19/images/tag_blue.png +0 -0
  145. data/rdoc/site/0.1.19/images/tag_green.png +0 -0
  146. data/rdoc/site/0.1.19/images/transparent.png +0 -0
  147. data/rdoc/site/0.1.19/images/wrench.png +0 -0
  148. data/rdoc/site/0.1.19/images/wrench_orange.png +0 -0
  149. data/rdoc/site/0.1.19/images/zoom.png +0 -0
  150. data/rdoc/site/0.1.19/index.html +311 -0
  151. data/rdoc/site/0.1.19/js/darkfish.js +155 -0
  152. data/rdoc/site/0.1.19/js/jquery.js +18 -0
  153. data/rdoc/site/0.1.19/js/navigation.js +142 -0
  154. data/rdoc/site/0.1.19/js/search.js +94 -0
  155. data/rdoc/site/0.1.19/js/search_index.js +1 -0
  156. data/rdoc/site/0.1.19/js/searcher.js +228 -0
  157. data/rdoc/site/0.1.19/rdoc.css +543 -0
  158. data/rdoc/site/0.1.19/table_of_contents.html +1541 -0
  159. metadata +140 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b1235f5a25a31be0dc6c8291d2b81a2acf7f53a8
4
- data.tar.gz: 12b4bfce18a0dee640ee3192def3394c8ce404fe
3
+ metadata.gz: 538f4bb7721e53ea65e86fcd9dabe27a3def5f67
4
+ data.tar.gz: 4fa312d8415f9db8d1b29537c95749358252a598
5
5
  SHA512:
6
- metadata.gz: 23d165b074de631f79469f11ba947ccead4fd1cfce9b6219edec419db9abf9506167c498044a9bd2e606b2c5c6c08195eb94a6afe47641f29010caf4336ebd81
7
- data.tar.gz: 90e7d32a20a4d4fd697733e9c6a5194572836e1281d18f8927935649671438beec83c31d43d4cfdfc566ee4223eee15341a6ee4ecb3f0c399888fc7154db8187
6
+ metadata.gz: afe85d0df90e8f5114d1d929e9806c01077ea5bbb293c4cef5aa886dc8a678e8a29baf653de081306a1873f9702f0da1d99f7776976b603600b3c4e283b1fb11
7
+ data.tar.gz: cd73b96970c6fc5ce2e29e1965bccd66b32c26d051f542c707de49bd0f99063bcd0c0f83d56eb7528cb794d5f62d4dfb57e4ec899db76ae8b1a8c936d66eef86
data/Gemfile CHANGED
@@ -3,6 +3,7 @@ source "http://rubygems.org"
3
3
  gem "log4r", "~> 1.1"
4
4
  gem "i18n", "~> 0.6"
5
5
  gem "netrc", "~> 0.7"
6
+ gem "highline", "~> 1.6"
6
7
 
7
8
  gem "deep_merge", "~> 1.0"
8
9
  gem "multi_json", "~> 1.7"
@@ -106,6 +106,7 @@ DEPENDENCIES
106
106
  celluloid (~> 0.15)
107
107
  childprocess (~> 0.5)
108
108
  deep_merge (~> 1.0)
109
+ highline (~> 1.6)
109
110
  i18n (~> 0.6)
110
111
  jeweler (~> 2.0)
111
112
  log4r (~> 1.1)
data/TODO.rdoc CHANGED
@@ -1,13 +1,10 @@
1
1
  == Nucleon tasks to complete before 1.0 release
2
2
 
3
- * Namespace implementation
4
- * Meta (composite) actions
5
3
  * Execution plans
6
4
  * Error handling improvements
7
5
  * Full code documentation
8
6
  * Full coverage unit tests (starting with core Nucleon unit testing library)
9
7
  * Performance improvements
10
- * Ensure fault tolerance for Actor managers
11
8
  * Deeper GitHub API integration in project provider
12
9
  * UI console color profiles
13
10
  * Localization improvements
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.19
1
+ 0.2.0
@@ -1,3 +1,22 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ Signal.trap("INT") { exit 1 }
4
+
5
+ #---
6
+
2
7
  require 'nucleon'
8
+
9
+ # Set version info
10
+
11
+ module Nucleon; module Util; module CLI
12
+ class Parser
13
+ def version
14
+ version = Nucleon.VERSION
15
+ "Nucleon: #{version} (Apache License, Version 2.0) -- https://github.com/coralnexus/nucleon/tree/v#{version}"
16
+ end
17
+ end
18
+ end; end; end
19
+
20
+ # Execute
21
+
3
22
  exit(Nucleon.executable(ARGV, :nucleon))
@@ -44,7 +44,7 @@ class Config
44
44
  @properties = {}
45
45
 
46
46
  if defaults.is_a?(Hash) && ! defaults.empty?
47
- defaults = symbol_map(defaults)
47
+ defaults = symbol_map(defaults.clone)
48
48
  end
49
49
 
50
50
  case data
@@ -53,7 +53,7 @@ class Config
53
53
  when Hash
54
54
  @properties = {}
55
55
  if data.is_a?(Hash)
56
- @properties = Util::Data.merge([ defaults, symbol_map(data) ], force)
56
+ @properties = Util::Data.merge([ defaults, symbol_map(data.clone) ], force)
57
57
  end
58
58
  end
59
59
  end
@@ -83,8 +83,11 @@ class Config
83
83
  def fetch(data, keys, default = nil, format = false)
84
84
  if keys.is_a?(String) || keys.is_a?(Symbol)
85
85
  keys = [ keys ]
86
- end
87
- key = keys.shift.to_sym
86
+ end
87
+
88
+ keys = keys.flatten.compact
89
+ key = keys.shift.to_sym
90
+
88
91
  if data.has_key?(key)
89
92
  value = data[key]
90
93
 
@@ -105,6 +108,7 @@ class Config
105
108
  keys = [ keys ]
106
109
  end
107
110
 
111
+ keys = keys.flatten.compact
108
112
  key = keys.shift.to_sym
109
113
  has_key = data.has_key?(key)
110
114
  existing = {
@@ -203,7 +207,7 @@ class Config
203
207
 
204
208
  case properties
205
209
  when Hash
206
- data = [ @properties, symbol_map(properties) ]
210
+ data = [ @properties, symbol_map(properties.clone) ]
207
211
  data = data.reverse if import_type != :override
208
212
 
209
213
  @properties = Util::Data.merge(data, config)
@@ -217,7 +221,7 @@ class Config
217
221
  @properties = Util::Data.merge(data, config)
218
222
 
219
223
  when Array
220
- properties.each do |item|
224
+ properties.clone.each do |item|
221
225
  import_base(item, config)
222
226
  end
223
227
  end
@@ -242,7 +246,7 @@ class Config
242
246
  #---
243
247
 
244
248
  def export
245
- return @properties
249
+ return @properties.clone
246
250
  end
247
251
 
248
252
  #-----------------------------------------------------------------------------
@@ -0,0 +1,338 @@
1
+
2
+ module Nucleon
3
+ class Environment
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Constructor / Destructor
7
+
8
+ def initialize
9
+ @plugin_types = {}
10
+
11
+ @load_info = {}
12
+ @active_info = {}
13
+ end
14
+
15
+ #-----------------------------------------------------------------------------
16
+ # Plugin type accessor / modifiers
17
+
18
+ def namespaces
19
+ @plugin_types.keys
20
+ end
21
+
22
+ #---
23
+
24
+ def plugin_types(namespace)
25
+ namespace = namespace.to_sym
26
+
27
+ return [] unless @plugin_types.has_key?(namespace)
28
+ @plugin_types[namespace].keys
29
+ end
30
+
31
+ #---
32
+
33
+ def define_plugin_type(namespace, plugin_type, default_provider = nil)
34
+ namespace = namespace.to_sym
35
+
36
+ @plugin_types[namespace] = {} unless @plugin_types.has_key?(namespace)
37
+ @plugin_types[namespace][sanitize_id(plugin_type)] = default_provider
38
+ end
39
+
40
+ #---
41
+
42
+ def define_plugin_types(namespace, type_info)
43
+ if type_info.is_a?(Hash)
44
+ type_info.each do |plugin_type, default_provider|
45
+ define_plugin_type(namespace, plugin_type, default_provider)
46
+ end
47
+ end
48
+ end
49
+
50
+ #---
51
+
52
+ def plugin_type_defined?(namespace, plugin_type)
53
+ namespace = namespace.to_sym
54
+
55
+ return false unless @plugin_types.has_key?(namespace)
56
+ @plugin_types[namespace].has_key?(sanitize_id(plugin_type))
57
+ end
58
+
59
+ #---
60
+
61
+ def plugin_type_default(namespace, plugin_type)
62
+ namespace = namespace.to_sym
63
+
64
+ return nil unless @plugin_types.has_key?(namespace)
65
+ @plugin_types[namespace][sanitize_id(plugin_type)]
66
+ end
67
+
68
+ #-----------------------------------------------------------------------------
69
+ # Loaded plugin accessor / modifiers
70
+
71
+ def define_plugin(namespace, plugin_type, base_path, file, &code)
72
+ namespace = namespace.to_sym
73
+ plugin_type = sanitize_id(plugin_type)
74
+
75
+ @load_info[namespace] = {} unless @load_info.has_key?(namespace)
76
+ @load_info[namespace][plugin_type] = {} unless @load_info[namespace].has_key?(plugin_type)
77
+
78
+ plugin_info = parse_plugin_info(namespace, plugin_type, base_path, file)
79
+
80
+ unless @load_info[namespace][plugin_type].has_key?(plugin_info[:provider])
81
+ data = {
82
+ :namespace => namespace,
83
+ :type => plugin_type,
84
+ :file => file,
85
+ :provider => plugin_info[:provider],
86
+ :directory => plugin_info[:directory],
87
+ :class_components => plugin_info[:class_components]
88
+ }
89
+ code.call(data) if code
90
+
91
+ @load_info[namespace][plugin_type][plugin_info[:provider]] = data
92
+ end
93
+ end
94
+
95
+ #---
96
+
97
+ def loaded_plugin(namespace, plugin_type, provider)
98
+ namespace = namespace.to_sym
99
+ plugin_type = sanitize_id(plugin_type)
100
+ provider = sanitize_id(provider)
101
+ info = nil
102
+
103
+ if @load_info.has_key?(namespace) &&
104
+ @load_info[namespace].has_key?(plugin_type) &&
105
+ @load_info[namespace][plugin_type].has_key?(provider)
106
+
107
+ info = @load_info[namespace][plugin_type][provider]
108
+ end
109
+ info
110
+ end
111
+
112
+ #---
113
+
114
+ def loaded_plugins(namespace = nil, plugin_type = nil, provider = nil, default = {})
115
+ namespace = namespace.to_sym if namespace
116
+ plugin_type = sanitize_id(plugin_type) if plugin_type
117
+ provider = sanitize_id(provider) if provider
118
+ results = default
119
+
120
+ if namespace && @load_info.has_key?(namespace)
121
+ if plugin_type && @load_info[namespace].has_key?(plugin_type)
122
+ if provider && @load_info[namespace][plugin_type].has_key?(provider)
123
+ results = @load_info[namespace][plugin_type][provider]
124
+ elsif ! provider
125
+ results = @load_info[namespace][plugin_type]
126
+ end
127
+ elsif ! plugin_type
128
+ results = @load_info[namespace]
129
+ end
130
+ elsif ! namespace
131
+ results = @load_info
132
+ end
133
+ results
134
+ end
135
+
136
+ #---
137
+
138
+ def plugin_has_type?(namespace, plugin_type)
139
+ namespace = namespace.to_sym
140
+
141
+ return false unless @load_info.has_key?(namespace)
142
+ @load_info[namespace].has_key?(sanitize_id(plugin_type))
143
+ end
144
+
145
+ #---
146
+
147
+ def plugin_has_provider?(namespace, plugin_type, provider)
148
+ namespace = namespace.to_sym
149
+ plugin_type = sanitize_id(plugin_type)
150
+ provider = sanitize_id(provider)
151
+
152
+ return false unless @load_info.has_key?(namespace) && @load_info[namespace].has_key?(plugin_type)
153
+ @load_info[namespace][plugin_type].has_key?(provider)
154
+ end
155
+
156
+ #-----------------------------------------------------------------------------
157
+ # Active plugin accessor / modifiers
158
+
159
+ def create_plugin(namespace, plugin_type, provider, options = {}, &code)
160
+ namespace = namespace.to_sym
161
+ plugin_type = sanitize_id(plugin_type)
162
+ provider = sanitize_id(provider)
163
+
164
+ unless plugin_type_defined?(namespace, plugin_type)
165
+ return nil
166
+ end
167
+
168
+ if type_info = loaded_plugin(namespace, plugin_type, provider)
169
+ ids = Util::Data.array(type_info[:class].register_ids).flatten
170
+ instance_options = Config.new(options).export
171
+ instance_options = Util::Data.subset(instance_options, ids, true)
172
+ instance_name = "#{provider}_" + Nucleon.sha1(instance_options)
173
+
174
+ @active_info[namespace] = {} unless @active_info.has_key?(namespace)
175
+ @active_info[namespace][plugin_type] = {} unless @active_info[namespace].has_key?(plugin_type)
176
+
177
+ unless instance_name && @active_info[namespace][plugin_type].has_key?(instance_name)
178
+ type_info[:instance_name] = instance_name
179
+
180
+ options = code.call(type_info, options) if code
181
+ plugin = type_info[:class].new(namespace, plugin_type, provider, options)
182
+
183
+ @active_info[namespace][plugin_type][instance_name] = plugin
184
+ end
185
+ return @active_info[namespace][plugin_type][instance_name]
186
+ end
187
+ nil
188
+ end
189
+
190
+ #---
191
+
192
+ def get_plugin(namespace, plugin_type, plugin_name)
193
+ namespace = namespace.to_sym
194
+ plugin_type = sanitize_id(plugin_type)
195
+
196
+ if @active_info.has_key?(namespace) && @active_info[namespace].has_key?(plugin_type)
197
+ @active_info[namespace][plugin_type].each do |instance_name, plugin|
198
+ if plugin.plugin_name.to_s == plugin_name.to_s
199
+ return plugin
200
+ end
201
+ end
202
+ end
203
+ nil
204
+ end
205
+
206
+ #---
207
+
208
+ def remove_plugin(namespace, plugin_type, instance_name, &code)
209
+ namespace = namespace.to_sym
210
+ plugin_type = sanitize_id(plugin_type)
211
+
212
+ if @active_info.has_key?(namespace) && @active_info[namespace].has_key?(plugin_type)
213
+ plugin = @active_info[namespace][plugin_type]
214
+ @active_info[namespace][plugin_type].delete(instance_name)
215
+ code.call(plugin) if code
216
+ end
217
+ end
218
+
219
+ #---
220
+
221
+ def active_plugins(namespace = nil, plugin_type = nil, provider = nil)
222
+ namespace = namespace.to_sym if namespace
223
+ plugin_type = sanitize_id(plugin_type) if plugin_type
224
+ provider = sanitize_id(provider) if provider
225
+ results = {}
226
+
227
+ if namespace && @active_info.has_key?(namespace)
228
+ if plugin_type && @active_info[namespace].has_key?(plugin_type)
229
+ if provider && ! @active_info[namespace][plugin_type].keys.empty?
230
+ @active_info[namespace][plugin_type].each do |instance_name, plugin|
231
+ plugin = @active_info[namespace][plugin_type][instance_name]
232
+ results[instance_name] = plugin if plugin.plugin_provider == provider
233
+ end
234
+ elsif ! provider
235
+ results = @active_info[namespace][plugin_type]
236
+ end
237
+ elsif ! plugin_type
238
+ results = @active_info[namespace]
239
+ end
240
+ elsif ! namespace
241
+ results = @active_info
242
+ end
243
+ results
244
+ end
245
+
246
+ #-----------------------------------------------------------------------------
247
+ # Utilities
248
+
249
+ def class_name(name, separator = '::', want_array = FALSE)
250
+ components = []
251
+
252
+ case name
253
+ when String, Symbol
254
+ components = name.to_s.split(separator)
255
+ when Array
256
+ components = name
257
+ end
258
+
259
+ components.collect! do |value|
260
+ value = value.to_s.strip
261
+ value[0] = value.capitalize[0] if value =~ /^[a-z]/
262
+ value
263
+ end
264
+
265
+ if want_array
266
+ return components
267
+ end
268
+ components.join(separator)
269
+ end
270
+
271
+ #---
272
+
273
+ def class_const(name, separator = '::')
274
+ components = class_name(name, separator, TRUE)
275
+ constant = Object
276
+
277
+ components.each do |component|
278
+ constant = constant.const_defined?(component) ?
279
+ constant.const_get(component) :
280
+ constant.const_missing(component)
281
+ end
282
+ constant
283
+ end
284
+
285
+ #---
286
+
287
+ def sanitize_id(id_component)
288
+ id_component.to_s.gsub(/([a-z0-9])(?:\-|\_)?([A-Z])/, '\1_\2').downcase.to_sym
289
+ end
290
+ protected :sanitize_id
291
+
292
+ #---
293
+
294
+ def sanitize_class(class_component)
295
+ class_component.to_s.split('_').collect {|elem| elem.slice(0,1).capitalize + elem.slice(1..-1) }.join('')
296
+ end
297
+ protected :sanitize_class
298
+
299
+ #---
300
+
301
+ def plugin_class(namespace, plugin_type)
302
+ class_const([ sanitize_class(namespace), :plugin, sanitize_class(plugin_type) ])
303
+ end
304
+
305
+ #---
306
+
307
+ def parse_plugin_info(namespace, plugin_type, base_path, file)
308
+ dir_components = base_path.split(File::SEPARATOR)
309
+ file_components = file.split(File::SEPARATOR)
310
+
311
+ file_name = file_components.pop.sub(/\.rb/, '')
312
+ directory = file_components.join(File::SEPARATOR)
313
+
314
+ file_class = sanitize_class(file_name)
315
+ group_components = file_components - dir_components
316
+
317
+ class_components = [ sanitize_class(namespace), sanitize_class(plugin_type) ]
318
+
319
+ if ! group_components.empty?
320
+ group_name = group_components.collect {|elem| elem.downcase }.join('_')
321
+ provider = [ group_name, file_name ].join('_')
322
+
323
+ group_components = group_components.collect {|elem| sanitize_class(elem) }
324
+ class_components = [ class_components, group_components, file_class ].flatten
325
+ else
326
+ provider = file_name
327
+ class_components = [ class_components, file_class ].flatten
328
+ end
329
+
330
+ {
331
+ :directory => directory,
332
+ :provider => sanitize_id(provider),
333
+ :class_components => class_components
334
+ }
335
+ end
336
+ protected :parse_plugin_info
337
+ end
338
+ end