├── .gitignore
├── ExampleApplication
├── English.lproj
│ ├── InfoPlist.strings
│ └── MainMenu.nib
│ │ ├── designable.nib
│ │ └── keyedobjects.nib
├── Example.fscript
├── Example.js
├── Example.lua
├── Example.nu
├── Example.pl
├── Example.py
├── Example.rb
├── Example.scpt
├── ExampleApplication.sdef
├── ExampleApplication.xcodeproj
│ ├── TemplateIcon.icns
│ ├── ghansard.mode1v3
│ ├── ghansard.pbxuser
│ └── project.pbxproj
├── ExampleApplication_Prefix.pch
├── ExampleController.h
├── ExampleController.m
├── ExampleObjCPlugin-Info.plist
├── ExamplePlugin.h
├── ExamplePlugin.m
├── Info.plist
├── NSApplication+Applescript.h
├── NSApplication+Applescript.m
└── main.m
├── README.markdown
├── documentation
├── Applescript Plugin Example.markdown
├── Nu support.markdown
├── Perl support.markdown
├── Python support.markdown
└── Ruby support.markdown
└── src
├── ApplescriptPluginManager.h
├── ApplescriptPluginManager.m
├── FScriptPlugInManager.h
├── FScriptPlugInManager.m
├── JavascriptPluginManager.h
├── JavascriptPluginManager.m
├── LuaPluginManager.h
├── LuaPluginManager.m
├── NSApplescript+FCSAdditions.h
├── NSApplescript+FCSAdditions.m
├── NuPluginManager.h
├── NuPluginManager.m
├── ObjCPluginManager.h
├── ObjCPluginManager.m
├── PerlPluginManager.h
├── PerlPluginManager.m
├── PluginManager.h
├── PluginManager.m
├── PluginManagerApplescriptIncludes.h
├── PluginManagerProtocol.h
├── PythonPluginManager.h
├── PythonPluginManager.m
├── RubyPluginManager.h
└── RubyPluginManager.m
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | build/
--------------------------------------------------------------------------------
/ExampleApplication/English.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Grayson/pluginmanager/0b59727302ba563d393a66bc62612459b4fea2ba/ExampleApplication/English.lproj/InfoPlist.strings
--------------------------------------------------------------------------------
/ExampleApplication/English.lproj/MainMenu.nib/keyedobjects.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Grayson/pluginmanager/0b59727302ba563d393a66bc62612459b4fea2ba/ExampleApplication/English.lproj/MainMenu.nib/keyedobjects.nib
--------------------------------------------------------------------------------
/ExampleApplication/Example.fscript:
--------------------------------------------------------------------------------
1 | actionProperty := [ 'label-click' ].
2 | actionEnable := [:forValue :withValue| YES].
3 | actionTitle := [:forValue :withValue| 'F-Script test'].
4 | actionPerform := [:forValue :withValue| sys log:forValue].
--------------------------------------------------------------------------------
/ExampleApplication/Example.js:
--------------------------------------------------------------------------------
1 | function actionProperty() {
2 | return "label-click";
3 | }
4 |
5 | function actionEnable(forValue, withValue) {
6 | return true;
7 | }
8 |
9 | function actionTitle(forValue, withValue) {
10 | return "javascript test";
11 | }
12 |
13 | function actionPerform(forValue, withValue) {
14 | log("Javascript");
15 | }
--------------------------------------------------------------------------------
/ExampleApplication/Example.lua:
--------------------------------------------------------------------------------
1 | function actionProperty()
2 | return "label-click"
3 | end
4 |
5 | function actionEnable( withValue, forValue )
6 | return true
7 | end
8 |
9 | function actionTitle( withValue, forValue )
10 | return "Lua test"
11 | end
12 |
13 | function actionPerform( withValue, forValue )
14 | print(withValue:description())
15 | end
--------------------------------------------------------------------------------
/ExampleApplication/Example.nu:
--------------------------------------------------------------------------------
1 | (function actionProperty () "label-click")
2 | (function actionEnable (forValue withValue) YES)
3 | (function actionTitle (forValue withValue) "Nu test")
4 | (function actionPerform (forValue withValue) (puts (forValue description)))
--------------------------------------------------------------------------------
/ExampleApplication/Example.pl:
--------------------------------------------------------------------------------
1 | # use Foundation;
2 | use CamelBones qw(:All);
3 |
4 | sub actionProperty {
5 | return "label-click";
6 | }
7 |
8 | sub actionEnable {
9 | my ($withValue, $forValue) = @_;
10 | return 1;
11 | }
12 |
13 | sub actionTitle {
14 | my ($withValue, $forValue) = @_;
15 | return "Perl example";
16 | }
17 |
18 | sub actionPerform {
19 | my ($withValue, $forValue) = @_;
20 | print $withValue->description();
21 | }
22 |
--------------------------------------------------------------------------------
/ExampleApplication/Example.py:
--------------------------------------------------------------------------------
1 | def actionProperty():
2 | return "label-click"
3 |
4 | def actionEnable( withValue, forValue ):
5 | return True
6 |
7 | def actionTitle( withValue, forValue ):
8 | return "Python example"
9 |
10 | def actionPerform( withValue, forValue ):
11 | print "Hello from Python"
--------------------------------------------------------------------------------
/ExampleApplication/Example.rb:
--------------------------------------------------------------------------------
1 | def actionProperty
2 | puts "Inside actionProperty"
3 | "label-click"
4 | end
5 |
6 | def actionEnable(withValue, forValue)
7 | true
8 | end
9 |
10 | def actionTitle(withValue, forValue)
11 | return "Ruby example"
12 | end
13 |
14 | def actionPerform(withValue, forValue)
15 | puts withValue
16 | puts forValue
17 | end
18 |
--------------------------------------------------------------------------------
/ExampleApplication/Example.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Grayson/pluginmanager/0b59727302ba563d393a66bc62612459b4fea2ba/ExampleApplication/Example.scpt
--------------------------------------------------------------------------------
/ExampleApplication/ExampleApplication.sdef:
--------------------------------------------------------------------------------
1 |
2 |
3 |
69 |
70 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
--------------------------------------------------------------------------------
/ExampleApplication/ExampleApplication.xcodeproj/TemplateIcon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Grayson/pluginmanager/0b59727302ba563d393a66bc62612459b4fea2ba/ExampleApplication/ExampleApplication.xcodeproj/TemplateIcon.icns
--------------------------------------------------------------------------------
/ExampleApplication/ExampleApplication.xcodeproj/ghansard.pbxuser:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | 1DC322E60F3B74730011E197 /* ExampleApplication */ = {
4 | isa = PBXExecutable;
5 | activeArgIndices = (
6 | );
7 | argumentStrings = (
8 | );
9 | autoAttachOnCrash = 1;
10 | breakpointsEnabled = 0;
11 | configStateDict = {
12 | };
13 | customDataFormattersEnabled = 1;
14 | debuggerPlugin = GDBDebugging;
15 | disassemblyDisplayState = 0;
16 | dylibVariantSuffix = "";
17 | enableDebugStr = 1;
18 | environmentEntries = (
19 | );
20 | executableSystemSymbolLevel = 0;
21 | executableUserSymbolLevel = 0;
22 | libgmallocEnabled = 0;
23 | name = ExampleApplication;
24 | savedGlobals = {
25 | };
26 | sourceDirectories = (
27 | );
28 | variableFormatDictionary = {
29 | };
30 | };
31 | 1DC322F40F3B747D0011E197 /* Source Control */ = {
32 | isa = PBXSourceControlManager;
33 | fallbackIsa = XCSourceControlManager;
34 | isSCMEnabled = 0;
35 | scmConfiguration = {
36 | };
37 | };
38 | 1DC322F50F3B747D0011E197 /* Code sense */ = {
39 | isa = PBXCodeSenseManager;
40 | indexTemplatePath = "";
41 | };
42 | 1DC322F70F3B74FA0011E197 /* ApplescriptPluginManager.h */ = {
43 | uiCtxt = {
44 | sepNavIntBoundsRect = "{{0, 0}, {439, 420}}";
45 | sepNavSelRange = "{747, 0}";
46 | sepNavVisRange = "{397, 350}";
47 | };
48 | };
49 | 1DC322F80F3B74FA0011E197 /* ApplescriptPluginManager.m */ = {
50 | uiCtxt = {
51 | sepNavIntBoundsRect = "{{0, 0}, {720, 1596}}";
52 | sepNavSelRange = "{2914, 0}";
53 | sepNavVisRange = "{3099, 542}";
54 | };
55 | };
56 | 1DC322FA0F3B74FA0011E197 /* FScriptPlugInManager.m */ = {
57 | uiCtxt = {
58 | sepNavIntBoundsRect = "{{0, 0}, {439, 1554}}";
59 | sepNavSelRange = "{3097, 0}";
60 | sepNavVisRange = "{866, 568}";
61 | };
62 | };
63 | 1DC322FC0F3B74FA0011E197 /* JavascriptPluginManager.m */ = {
64 | uiCtxt = {
65 | sepNavIntBoundsRect = "{{0, 0}, {439, 1596}}";
66 | sepNavSelRange = "{1497, 2}";
67 | sepNavVisRange = "{1266, 465}";
68 | };
69 | };
70 | 1DC322FE0F3B74FA0011E197 /* LuaPluginManager.m */ = {
71 | uiCtxt = {
72 | sepNavIntBoundsRect = "{{0, 0}, {439, 2100}}";
73 | sepNavSelRange = "{3913, 0}";
74 | sepNavVisRange = "{753, 497}";
75 | };
76 | };
77 | 1DC323000F3B74FA0011E197 /* NuPluginManager.m */ = {
78 | uiCtxt = {
79 | sepNavIntBoundsRect = "{{0, 0}, {439, 1540}}";
80 | sepNavSelRange = "{2743, 0}";
81 | sepNavVisRange = "{704, 479}";
82 | };
83 | };
84 | 1DC323080F3B74FA0011E197 /* PythonPluginManager.m */ = {
85 | uiCtxt = {
86 | sepNavIntBoundsRect = "{{0, 0}, {720, 3752}}";
87 | sepNavSelRange = "{4197, 5}";
88 | sepNavVisRange = "{3891, 606}";
89 | };
90 | };
91 | 1DC323600F3B75910011E197 /* NSApplescript+FCSAdditions.m */ = {
92 | uiCtxt = {
93 | sepNavIntBoundsRect = "{{0, 0}, {439, 2310}}";
94 | sepNavSelRange = "{5748, 0}";
95 | sepNavVisRange = "{5236, 504}";
96 | };
97 | };
98 | 1DC323C70F3B77990011E197 /* ExampleObjCPlugin */ = {
99 | activeExec = 0;
100 | };
101 | 1DC323D10F3B77D80011E197 /* ExamplePlugin.m */ = {
102 | uiCtxt = {
103 | sepNavIntBoundsRect = "{{0, 0}, {720, 364}}";
104 | sepNavSelRange = "{572, 5}";
105 | sepNavVisRange = "{220, 393}";
106 | };
107 | };
108 | 1DC323EB0F3B795E0011E197 /* ExampleController.m */ = {
109 | uiCtxt = {
110 | sepNavIntBoundsRect = "{{0, 0}, {720, 784}}";
111 | sepNavSelRange = "{1079, 0}";
112 | sepNavVisRange = "{840, 580}";
113 | };
114 | };
115 | 1DC324310F3B89D30011E197 /* ExampleApplication.sdef */ = {
116 | uiCtxt = {
117 | sepNavWindowFrame = "{{15, 9}, {795, 864}}";
118 | };
119 | };
120 | 1DD73B870F3CC97C00552B38 /* malloc_error_break */ = {
121 | isa = PBXSymbolicBreakpoint;
122 | actions = (
123 | 1DD73B9D0F3CCA0A00552B38 /* XCBreakpointLogAction */,
124 | );
125 | breakpointStyle = 1;
126 | continueAfterActions = 0;
127 | countType = 0;
128 | delayBeforeContinue = 0;
129 | hitCount = 1;
130 | ignoreCount = 0;
131 | location = libSystem.B.dylib;
132 | modificationTime = 255642084.819161;
133 | state = 1;
134 | symbolName = malloc_error_break;
135 | };
136 | 1DD73B9D0F3CCA0A00552B38 /* XCBreakpointLogAction */ = {
137 | isa = XCBreakpointLogAction;
138 | fallbackIsa = XCBreakpointAction;
139 | logMessage = 1;
140 | message = asf;
141 | speakMessage = 0;
142 | useDebuggerSideImplementation = 0;
143 | };
144 | 1DF38DE40F3E19DF00431004 /* PerlPluginManager.m */ = {
145 | uiCtxt = {
146 | sepNavIntBoundsRect = "{{0, 0}, {439, 1540}}";
147 | sepNavSelRange = "{2785, 0}";
148 | sepNavVisRange = "{231, 344}";
149 | };
150 | };
151 | 29B97313FDCFA39411CA2CEA /* Project object */ = {
152 | activeArchitecture = i386;
153 | activeBuildConfigurationName = Debug;
154 | activeExecutable = 1DC322E60F3B74730011E197 /* ExampleApplication */;
155 | activeTarget = 8D1107260486CEB800E47090 /* ExampleApplication */;
156 | addToTargets = (
157 | 8D1107260486CEB800E47090 /* ExampleApplication */,
158 | );
159 | breakpoints = (
160 | 1DD73B870F3CC97C00552B38 /* malloc_error_break */,
161 | );
162 | codeSenseManager = 1DC322F50F3B747D0011E197 /* Code sense */;
163 | executables = (
164 | 1DC322E60F3B74730011E197 /* ExampleApplication */,
165 | );
166 | perUserDictionary = {
167 | "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = {
168 | PBXFileTableDataSourceColumnSortingDirectionKey = 1;
169 | PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID;
170 | PBXFileTableDataSourceColumnWidthsKey = (
171 | 20,
172 | 20,
173 | 198,
174 | 20,
175 | 99,
176 | 99,
177 | 29,
178 | 20,
179 | );
180 | PBXFileTableDataSourceColumnsKey = (
181 | PBXBreakpointsDataSource_ActionID,
182 | PBXBreakpointsDataSource_TypeID,
183 | PBXBreakpointsDataSource_BreakpointID,
184 | PBXBreakpointsDataSource_UseID,
185 | PBXBreakpointsDataSource_LocationID,
186 | PBXBreakpointsDataSource_ConditionID,
187 | PBXBreakpointsDataSource_IgnoreCountID,
188 | PBXBreakpointsDataSource_ContinueID,
189 | );
190 | };
191 | PBXConfiguration.PBXFileTableDataSource3.PBXErrorsWarningsDataSource = {
192 | PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
193 | PBXFileTableDataSourceColumnSortingKey = PBXErrorsWarningsDataSource_LocationID;
194 | PBXFileTableDataSourceColumnWidthsKey = (
195 | 20,
196 | 300,
197 | 133,
198 | );
199 | PBXFileTableDataSourceColumnsKey = (
200 | PBXErrorsWarningsDataSource_TypeID,
201 | PBXErrorsWarningsDataSource_MessageID,
202 | PBXErrorsWarningsDataSource_LocationID,
203 | );
204 | };
205 | PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = {
206 | PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
207 | PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID;
208 | PBXFileTableDataSourceColumnWidthsKey = (
209 | 22,
210 | 300,
211 | 131,
212 | );
213 | PBXFileTableDataSourceColumnsKey = (
214 | PBXExecutablesDataSource_ActiveFlagID,
215 | PBXExecutablesDataSource_NameID,
216 | PBXExecutablesDataSource_CommentsID,
217 | );
218 | };
219 | PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
220 | PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
221 | PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
222 | PBXFileTableDataSourceColumnWidthsKey = (
223 | 20,
224 | 243,
225 | 20,
226 | 48,
227 | 43,
228 | 43,
229 | 20,
230 | );
231 | PBXFileTableDataSourceColumnsKey = (
232 | PBXFileDataSource_FiletypeID,
233 | PBXFileDataSource_Filename_ColumnID,
234 | PBXFileDataSource_Built_ColumnID,
235 | PBXFileDataSource_ObjectSize_ColumnID,
236 | PBXFileDataSource_Errors_ColumnID,
237 | PBXFileDataSource_Warnings_ColumnID,
238 | PBXFileDataSource_Target_ColumnID,
239 | );
240 | };
241 | PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
242 | PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
243 | PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
244 | PBXFileTableDataSourceColumnWidthsKey = (
245 | 20,
246 | 203,
247 | 60,
248 | 20,
249 | 48,
250 | 43,
251 | 43,
252 | );
253 | PBXFileTableDataSourceColumnsKey = (
254 | PBXFileDataSource_FiletypeID,
255 | PBXFileDataSource_Filename_ColumnID,
256 | PBXTargetDataSource_PrimaryAttribute,
257 | PBXFileDataSource_Built_ColumnID,
258 | PBXFileDataSource_ObjectSize_ColumnID,
259 | PBXFileDataSource_Errors_ColumnID,
260 | PBXFileDataSource_Warnings_ColumnID,
261 | );
262 | };
263 | PBXPerProjectTemplateStateSaveDate = 257878641;
264 | PBXWorkspaceStateSaveDate = 257878641;
265 | };
266 | sourceControlManager = 1DC322F40F3B747D0011E197 /* Source Control */;
267 | userBuildSettings = {
268 | };
269 | };
270 | 8D1107260486CEB800E47090 /* ExampleApplication */ = {
271 | activeExec = 0;
272 | executables = (
273 | 1DC322E60F3B74730011E197 /* ExampleApplication */,
274 | );
275 | };
276 | 8D1107310486CEB800E47090 /* Info.plist */ = {
277 | uiCtxt = {
278 | sepNavIntBoundsRect = "{{0, 0}, {736, 751}}";
279 | sepNavSelRange = "{611, 17}";
280 | sepNavVisRange = "{0, 971}";
281 | sepNavWindowFrame = "{{15, 9}, {795, 864}}";
282 | };
283 | };
284 | }
285 |
--------------------------------------------------------------------------------
/ExampleApplication/ExampleApplication.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 45;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1D973ECE0F3BE83900437B6D /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D973ECD0F3BE83900437B6D /* AddressBook.framework */; };
11 | 1D9787380F5EED730093EA87 /* MacRuby.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D9787370F5EED730093EA87 /* MacRuby.framework */; };
12 | 1D9787B30F5F06780093EA87 /* FScriptPlugInManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC322FA0F3B74FA0011E197 /* FScriptPlugInManager.m */; };
13 | 1D9787B40F5F06790093EA87 /* ApplescriptPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC322F80F3B74FA0011E197 /* ApplescriptPluginManager.m */; };
14 | 1D9787B50F5F067A0093EA87 /* JavascriptPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC322FC0F3B74FA0011E197 /* JavascriptPluginManager.m */; };
15 | 1D9787B60F5F067A0093EA87 /* LuaPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC322FE0F3B74FA0011E197 /* LuaPluginManager.m */; };
16 | 1D9787B70F5F067B0093EA87 /* NSApplescript+FCSAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323600F3B75910011E197 /* NSApplescript+FCSAdditions.m */; };
17 | 1D9787B80F5F067C0093EA87 /* NuPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323000F3B74FA0011E197 /* NuPluginManager.m */; };
18 | 1D9787B90F5F067D0093EA87 /* ObjCPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323020F3B74FA0011E197 /* ObjCPluginManager.m */; };
19 | 1D9787BB0F5F067F0093EA87 /* PythonPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323080F3B74FA0011E197 /* PythonPluginManager.m */; };
20 | 1D9787BD0F5F068A0093EA87 /* Nu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DC323140F3B751A0011E197 /* Nu.framework */; };
21 | 1DC323110F3B74FA0011E197 /* PluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323040F3B74FA0011E197 /* PluginManager.m */; };
22 | 1DC323D20F3B77D80011E197 /* ExamplePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323D10F3B77D80011E197 /* ExamplePlugin.m */; };
23 | 1DC323D30F3B77DB0011E197 /* ExamplePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323D10F3B77D80011E197 /* ExamplePlugin.m */; };
24 | 1DC323D50F3B77E90011E197 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
25 | 1DC323DC0F3B78C90011E197 /* ExampleObjCPlugin.bundle in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DC323C80F3B77990011E197 /* ExampleObjCPlugin.bundle */; };
26 | 1DC323EC0F3B795E0011E197 /* ExampleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC323EB0F3B795E0011E197 /* ExampleController.m */; };
27 | 1DC3242E0F3B87190011E197 /* Example.scpt in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DC3242B0F3B870C0011E197 /* Example.scpt */; };
28 | 1DC324320F3B89D30011E197 /* ExampleApplication.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 1DC324310F3B89D30011E197 /* ExampleApplication.sdef */; };
29 | 1DD73BC20F3CD19700552B38 /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DC3234F0F3B752B0011E197 /* Python.framework */; };
30 | 1DD73BF90F3CD78100552B38 /* FScript.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DC323150F3B751A0011E197 /* FScript.framework */; };
31 | 1DD73BFA0F3CD78300552B38 /* JSCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DC323160F3B751A0011E197 /* JSCocoa.framework */; };
32 | 1DD73C0F0F3CD85600552B38 /* Example.lua in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DD73BFF0F3CD7D000552B38 /* Example.lua */; };
33 | 1DD73C100F3CD85600552B38 /* Example.js in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DD73C050F3CD7F200552B38 /* Example.js */; };
34 | 1DD73C110F3CD85600552B38 /* Example.fscript in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DD73C090F3CD82400552B38 /* Example.fscript */; };
35 | 1DD73C120F3CD85600552B38 /* Example.nu in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DD73C0B0F3CD83E00552B38 /* Example.nu */; };
36 | 1DD73C300F3CD9C800552B38 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DC323BD0F3B76C40011E197 /* Carbon.framework */; };
37 | 1DD73C5A0F3CF93500552B38 /* Example.py in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1D973F310F3BF36000437B6D /* Example.py */; };
38 | 1DD73C610F3CFA9F00552B38 /* NSApplication+Applescript.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DD73C600F3CFA9F00552B38 /* NSApplication+Applescript.m */; };
39 | 1DEF26DA0F4DE93F00F986A2 /* LuaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DEF26D90F4DE93F00F986A2 /* LuaCore.framework */; };
40 | 1DEF26FC0F4DE95700F986A2 /* Example.rb in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DD73B270F3CA06500552B38 /* Example.rb */; };
41 | 1DF38D770F3DE9AA00431004 /* RubyPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DC3230A0F3B74FA0011E197 /* RubyPluginManager.m */; };
42 | 1DF38DEB0F3E205F00431004 /* Example.pl in Resources */ = {isa = PBXBuildFile; fileRef = 1DF38DEA0F3E205F00431004 /* Example.pl */; };
43 | 1DF38DF70F3E20C400431004 /* Example.pl in Copy plugins */ = {isa = PBXBuildFile; fileRef = 1DF38DEA0F3E205F00431004 /* Example.pl */; };
44 | 8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
45 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
46 | 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
47 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
48 | /* End PBXBuildFile section */
49 |
50 | /* Begin PBXContainerItemProxy section */
51 | 1DC323D80F3B78950011E197 /* PBXContainerItemProxy */ = {
52 | isa = PBXContainerItemProxy;
53 | containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
54 | proxyType = 1;
55 | remoteGlobalIDString = 1DC323C70F3B77990011E197;
56 | remoteInfo = ExampleObjCPlugin;
57 | };
58 | /* End PBXContainerItemProxy section */
59 |
60 | /* Begin PBXCopyFilesBuildPhase section */
61 | 1DC323DE0F3B78CE0011E197 /* Copy plugins */ = {
62 | isa = PBXCopyFilesBuildPhase;
63 | buildActionMask = 2147483647;
64 | dstPath = "";
65 | dstSubfolderSpec = 13;
66 | files = (
67 | 1DEF26FC0F4DE95700F986A2 /* Example.rb in Copy plugins */,
68 | 1DF38DF70F3E20C400431004 /* Example.pl in Copy plugins */,
69 | 1DD73C5A0F3CF93500552B38 /* Example.py in Copy plugins */,
70 | 1DD73C0F0F3CD85600552B38 /* Example.lua in Copy plugins */,
71 | 1DD73C100F3CD85600552B38 /* Example.js in Copy plugins */,
72 | 1DD73C110F3CD85600552B38 /* Example.fscript in Copy plugins */,
73 | 1DD73C120F3CD85600552B38 /* Example.nu in Copy plugins */,
74 | 1DC3242E0F3B87190011E197 /* Example.scpt in Copy plugins */,
75 | 1DC323DC0F3B78C90011E197 /* ExampleObjCPlugin.bundle in Copy plugins */,
76 | );
77 | name = "Copy plugins";
78 | runOnlyForDeploymentPostprocessing = 0;
79 | };
80 | /* End PBXCopyFilesBuildPhase section */
81 |
82 | /* Begin PBXFileReference section */
83 | 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; };
84 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; };
85 | 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; };
86 | 1D973ECD0F3BE83900437B6D /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = /System/Library/Frameworks/AddressBook.framework; sourceTree = ""; };
87 | 1D973F310F3BF36000437B6D /* Example.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = Example.py; sourceTree = ""; };
88 | 1D9787370F5EED730093EA87 /* MacRuby.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MacRuby.framework; path = /Library/Frameworks/MacRuby.framework; sourceTree = ""; };
89 | 1DC322F70F3B74FA0011E197 /* ApplescriptPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplescriptPluginManager.h; sourceTree = ""; };
90 | 1DC322F80F3B74FA0011E197 /* ApplescriptPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ApplescriptPluginManager.m; sourceTree = ""; };
91 | 1DC322F90F3B74FA0011E197 /* FScriptPlugInManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FScriptPlugInManager.h; sourceTree = ""; };
92 | 1DC322FA0F3B74FA0011E197 /* FScriptPlugInManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FScriptPlugInManager.m; sourceTree = ""; };
93 | 1DC322FB0F3B74FA0011E197 /* JavascriptPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavascriptPluginManager.h; sourceTree = ""; };
94 | 1DC322FC0F3B74FA0011E197 /* JavascriptPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JavascriptPluginManager.m; sourceTree = ""; };
95 | 1DC322FD0F3B74FA0011E197 /* LuaPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LuaPluginManager.h; sourceTree = ""; };
96 | 1DC322FE0F3B74FA0011E197 /* LuaPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LuaPluginManager.m; sourceTree = ""; };
97 | 1DC322FF0F3B74FA0011E197 /* NuPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuPluginManager.h; sourceTree = ""; };
98 | 1DC323000F3B74FA0011E197 /* NuPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuPluginManager.m; sourceTree = ""; };
99 | 1DC323010F3B74FA0011E197 /* ObjCPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjCPluginManager.h; sourceTree = ""; };
100 | 1DC323020F3B74FA0011E197 /* ObjCPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCPluginManager.m; sourceTree = ""; };
101 | 1DC323030F3B74FA0011E197 /* PluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginManager.h; sourceTree = ""; };
102 | 1DC323040F3B74FA0011E197 /* PluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PluginManager.m; sourceTree = ""; };
103 | 1DC323050F3B74FA0011E197 /* PluginManagerApplescriptIncludes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginManagerApplescriptIncludes.h; sourceTree = ""; };
104 | 1DC323060F3B74FA0011E197 /* PluginManagerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginManagerProtocol.h; sourceTree = ""; };
105 | 1DC323070F3B74FA0011E197 /* PythonPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PythonPluginManager.h; sourceTree = ""; };
106 | 1DC323080F3B74FA0011E197 /* PythonPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PythonPluginManager.m; sourceTree = ""; };
107 | 1DC323090F3B74FA0011E197 /* RubyPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RubyPluginManager.h; sourceTree = ""; };
108 | 1DC3230A0F3B74FA0011E197 /* RubyPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RubyPluginManager.m; sourceTree = ""; };
109 | 1DC323140F3B751A0011E197 /* Nu.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nu.framework; path = /Library/Frameworks/Nu.framework; sourceTree = ""; };
110 | 1DC323150F3B751A0011E197 /* FScript.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FScript.framework; path = /Library/Frameworks/FScript.framework; sourceTree = ""; };
111 | 1DC323160F3B751A0011E197 /* JSCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JSCocoa.framework; path = /Library/Frameworks/JSCocoa.framework; sourceTree = ""; };
112 | 1DC3234F0F3B752B0011E197 /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /System/Library/Frameworks/Python.framework; sourceTree = ""; };
113 | 1DC3235F0F3B75910011E197 /* NSApplescript+FCSAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSApplescript+FCSAdditions.h"; sourceTree = ""; };
114 | 1DC323600F3B75910011E197 /* NSApplescript+FCSAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSApplescript+FCSAdditions.m"; sourceTree = ""; };
115 | 1DC323BD0F3B76C40011E197 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; };
116 | 1DC323C80F3B77990011E197 /* ExampleObjCPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleObjCPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
117 | 1DC323C90F3B77990011E197 /* ExampleObjCPlugin-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleObjCPlugin-Info.plist"; sourceTree = ""; };
118 | 1DC323D00F3B77D80011E197 /* ExamplePlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExamplePlugin.h; sourceTree = ""; };
119 | 1DC323D10F3B77D80011E197 /* ExamplePlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExamplePlugin.m; sourceTree = ""; };
120 | 1DC323EA0F3B795E0011E197 /* ExampleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleController.h; sourceTree = ""; };
121 | 1DC323EB0F3B795E0011E197 /* ExampleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleController.m; sourceTree = ""; };
122 | 1DC3242B0F3B870C0011E197 /* Example.scpt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.scpt; path = Example.scpt; sourceTree = ""; };
123 | 1DC324310F3B89D30011E197 /* ExampleApplication.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.sdef; path = ExampleApplication.sdef; sourceTree = ""; };
124 | 1DD73B270F3CA06500552B38 /* Example.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = Example.rb; sourceTree = ""; };
125 | 1DD73BFF0F3CD7D000552B38 /* Example.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Example.lua; sourceTree = ""; };
126 | 1DD73C050F3CD7F200552B38 /* Example.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = Example.js; sourceTree = ""; };
127 | 1DD73C090F3CD82400552B38 /* Example.fscript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Example.fscript; sourceTree = ""; };
128 | 1DD73C0B0F3CD83E00552B38 /* Example.nu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Example.nu; sourceTree = ""; };
129 | 1DD73C5F0F3CFA9F00552B38 /* NSApplication+Applescript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSApplication+Applescript.h"; sourceTree = ""; };
130 | 1DD73C600F3CFA9F00552B38 /* NSApplication+Applescript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSApplication+Applescript.m"; sourceTree = ""; };
131 | 1DEF26D90F4DE93F00F986A2 /* LuaCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LuaCore.framework; path = /Library/Frameworks/LuaCore.framework; sourceTree = ""; };
132 | 1DF38DCF0F3E19CC00431004 /* CamelBones.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CamelBones.framework; path = /Library/Frameworks/CamelBones.framework; sourceTree = ""; };
133 | 1DF38DE40F3E19DF00431004 /* PerlPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PerlPluginManager.m; sourceTree = ""; };
134 | 1DF38DE50F3E19DF00431004 /* PerlPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerlPluginManager.h; sourceTree = ""; };
135 | 1DF38DEA0F3E205F00431004 /* Example.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = Example.pl; sourceTree = ""; };
136 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
137 | 29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = ""; };
138 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; };
139 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; };
140 | 32CA4F630368D1EE00C91783 /* ExampleApplication_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleApplication_Prefix.pch; sourceTree = ""; };
141 | 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
142 | 8D1107320486CEB800E47090 /* ExampleApplication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleApplication.app; sourceTree = BUILT_PRODUCTS_DIR; };
143 | /* End PBXFileReference section */
144 |
145 | /* Begin PBXFrameworksBuildPhase section */
146 | 1DC323C60F3B77990011E197 /* Frameworks */ = {
147 | isa = PBXFrameworksBuildPhase;
148 | buildActionMask = 2147483647;
149 | files = (
150 | 1DC323D50F3B77E90011E197 /* Cocoa.framework in Frameworks */,
151 | );
152 | runOnlyForDeploymentPostprocessing = 0;
153 | };
154 | 8D11072E0486CEB800E47090 /* Frameworks */ = {
155 | isa = PBXFrameworksBuildPhase;
156 | buildActionMask = 2147483647;
157 | files = (
158 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
159 | 1D973ECE0F3BE83900437B6D /* AddressBook.framework in Frameworks */,
160 | 1DD73BC20F3CD19700552B38 /* Python.framework in Frameworks */,
161 | 1DD73BF90F3CD78100552B38 /* FScript.framework in Frameworks */,
162 | 1DD73BFA0F3CD78300552B38 /* JSCocoa.framework in Frameworks */,
163 | 1DD73C300F3CD9C800552B38 /* Carbon.framework in Frameworks */,
164 | 1DEF26DA0F4DE93F00F986A2 /* LuaCore.framework in Frameworks */,
165 | 1D9787380F5EED730093EA87 /* MacRuby.framework in Frameworks */,
166 | 1D9787BD0F5F068A0093EA87 /* Nu.framework in Frameworks */,
167 | );
168 | runOnlyForDeploymentPostprocessing = 0;
169 | };
170 | /* End PBXFrameworksBuildPhase section */
171 |
172 | /* Begin PBXGroup section */
173 | 080E96DDFE201D6D7F000001 /* Classes */ = {
174 | isa = PBXGroup;
175 | children = (
176 | 1DC323EA0F3B795E0011E197 /* ExampleController.h */,
177 | 1DC323EB0F3B795E0011E197 /* ExampleController.m */,
178 | 1DD73C5F0F3CFA9F00552B38 /* NSApplication+Applescript.h */,
179 | 1DD73C600F3CFA9F00552B38 /* NSApplication+Applescript.m */,
180 | );
181 | name = Classes;
182 | sourceTree = "";
183 | };
184 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
185 | isa = PBXGroup;
186 | children = (
187 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
188 | );
189 | name = "Linked Frameworks";
190 | sourceTree = "";
191 | };
192 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
193 | isa = PBXGroup;
194 | children = (
195 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */,
196 | 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
197 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */,
198 | );
199 | name = "Other Frameworks";
200 | sourceTree = "";
201 | };
202 | 19C28FACFE9D520D11CA2CBB /* Products */ = {
203 | isa = PBXGroup;
204 | children = (
205 | 8D1107320486CEB800E47090 /* ExampleApplication.app */,
206 | 1DC323C80F3B77990011E197 /* ExampleObjCPlugin.bundle */,
207 | );
208 | name = Products;
209 | sourceTree = "";
210 | };
211 | 1DC322F60F3B74FA0011E197 /* PluginManager */ = {
212 | isa = PBXGroup;
213 | children = (
214 | 1DF38DE40F3E19DF00431004 /* PerlPluginManager.m */,
215 | 1DF38DE50F3E19DF00431004 /* PerlPluginManager.h */,
216 | 1DC3235F0F3B75910011E197 /* NSApplescript+FCSAdditions.h */,
217 | 1DC323600F3B75910011E197 /* NSApplescript+FCSAdditions.m */,
218 | 1DC322F70F3B74FA0011E197 /* ApplescriptPluginManager.h */,
219 | 1DC322F80F3B74FA0011E197 /* ApplescriptPluginManager.m */,
220 | 1DC322F90F3B74FA0011E197 /* FScriptPlugInManager.h */,
221 | 1DC322FA0F3B74FA0011E197 /* FScriptPlugInManager.m */,
222 | 1DC322FB0F3B74FA0011E197 /* JavascriptPluginManager.h */,
223 | 1DC322FC0F3B74FA0011E197 /* JavascriptPluginManager.m */,
224 | 1DC322FD0F3B74FA0011E197 /* LuaPluginManager.h */,
225 | 1DC322FE0F3B74FA0011E197 /* LuaPluginManager.m */,
226 | 1DC322FF0F3B74FA0011E197 /* NuPluginManager.h */,
227 | 1DC323000F3B74FA0011E197 /* NuPluginManager.m */,
228 | 1DC323010F3B74FA0011E197 /* ObjCPluginManager.h */,
229 | 1DC323020F3B74FA0011E197 /* ObjCPluginManager.m */,
230 | 1DC323030F3B74FA0011E197 /* PluginManager.h */,
231 | 1DC323040F3B74FA0011E197 /* PluginManager.m */,
232 | 1DC323050F3B74FA0011E197 /* PluginManagerApplescriptIncludes.h */,
233 | 1DC323060F3B74FA0011E197 /* PluginManagerProtocol.h */,
234 | 1DC323070F3B74FA0011E197 /* PythonPluginManager.h */,
235 | 1DC323080F3B74FA0011E197 /* PythonPluginManager.m */,
236 | 1DC323090F3B74FA0011E197 /* RubyPluginManager.h */,
237 | 1DC3230A0F3B74FA0011E197 /* RubyPluginManager.m */,
238 | );
239 | name = PluginManager;
240 | path = ../src;
241 | sourceTree = SOURCE_ROOT;
242 | };
243 | 1DC323CE0F3B77B40011E197 /* ExampleApplication */ = {
244 | isa = PBXGroup;
245 | children = (
246 | 1DC3242A0F3B86790011E197 /* PlugIns */,
247 | 1DC322F60F3B74FA0011E197 /* PluginManager */,
248 | 080E96DDFE201D6D7F000001 /* Classes */,
249 | 29B97315FDCFA39411CA2CEA /* Other Sources */,
250 | 29B97317FDCFA39411CA2CEA /* Resources */,
251 | );
252 | name = ExampleApplication;
253 | sourceTree = "";
254 | };
255 | 1DC323CF0F3B77BE0011E197 /* ExampleObjCPlugin */ = {
256 | isa = PBXGroup;
257 | children = (
258 | 1DC323C90F3B77990011E197 /* ExampleObjCPlugin-Info.plist */,
259 | 1DC323D00F3B77D80011E197 /* ExamplePlugin.h */,
260 | 1DC323D10F3B77D80011E197 /* ExamplePlugin.m */,
261 | );
262 | name = ExampleObjCPlugin;
263 | sourceTree = "";
264 | };
265 | 1DC3242A0F3B86790011E197 /* PlugIns */ = {
266 | isa = PBXGroup;
267 | children = (
268 | 1DC3242B0F3B870C0011E197 /* Example.scpt */,
269 | 1D973F310F3BF36000437B6D /* Example.py */,
270 | 1DD73B270F3CA06500552B38 /* Example.rb */,
271 | 1DD73BFF0F3CD7D000552B38 /* Example.lua */,
272 | 1DD73C050F3CD7F200552B38 /* Example.js */,
273 | 1DD73C090F3CD82400552B38 /* Example.fscript */,
274 | 1DD73C0B0F3CD83E00552B38 /* Example.nu */,
275 | 1DF38DEA0F3E205F00431004 /* Example.pl */,
276 | );
277 | name = PlugIns;
278 | sourceTree = "";
279 | };
280 | 29B97314FDCFA39411CA2CEA /* ExampleApplication */ = {
281 | isa = PBXGroup;
282 | children = (
283 | 1DC323CE0F3B77B40011E197 /* ExampleApplication */,
284 | 1DC323CF0F3B77BE0011E197 /* ExampleObjCPlugin */,
285 | 29B97323FDCFA39411CA2CEA /* Frameworks */,
286 | 19C28FACFE9D520D11CA2CBB /* Products */,
287 | );
288 | name = ExampleApplication;
289 | sourceTree = "";
290 | };
291 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = {
292 | isa = PBXGroup;
293 | children = (
294 | 32CA4F630368D1EE00C91783 /* ExampleApplication_Prefix.pch */,
295 | 29B97316FDCFA39411CA2CEA /* main.m */,
296 | );
297 | name = "Other Sources";
298 | sourceTree = "";
299 | };
300 | 29B97317FDCFA39411CA2CEA /* Resources */ = {
301 | isa = PBXGroup;
302 | children = (
303 | 1DC324310F3B89D30011E197 /* ExampleApplication.sdef */,
304 | 8D1107310486CEB800E47090 /* Info.plist */,
305 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
306 | 29B97318FDCFA39411CA2CEA /* MainMenu.nib */,
307 | );
308 | name = Resources;
309 | sourceTree = "";
310 | };
311 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
312 | isa = PBXGroup;
313 | children = (
314 | 1D9787370F5EED730093EA87 /* MacRuby.framework */,
315 | 1DEF26D90F4DE93F00F986A2 /* LuaCore.framework */,
316 | 1D973ECD0F3BE83900437B6D /* AddressBook.framework */,
317 | 1DC323BD0F3B76C40011E197 /* Carbon.framework */,
318 | 1DC3234F0F3B752B0011E197 /* Python.framework */,
319 | 1DC323140F3B751A0011E197 /* Nu.framework */,
320 | 1DC323150F3B751A0011E197 /* FScript.framework */,
321 | 1DC323160F3B751A0011E197 /* JSCocoa.framework */,
322 | 1DF38DCF0F3E19CC00431004 /* CamelBones.framework */,
323 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
324 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
325 | );
326 | name = Frameworks;
327 | sourceTree = "";
328 | };
329 | /* End PBXGroup section */
330 |
331 | /* Begin PBXNativeTarget section */
332 | 1DC323C70F3B77990011E197 /* ExampleObjCPlugin */ = {
333 | isa = PBXNativeTarget;
334 | buildConfigurationList = 1DC323CD0F3B779C0011E197 /* Build configuration list for PBXNativeTarget "ExampleObjCPlugin" */;
335 | buildPhases = (
336 | 1DC323C40F3B77990011E197 /* Resources */,
337 | 1DC323C50F3B77990011E197 /* Sources */,
338 | 1DC323C60F3B77990011E197 /* Frameworks */,
339 | );
340 | buildRules = (
341 | );
342 | dependencies = (
343 | );
344 | name = ExampleObjCPlugin;
345 | productName = ExampleObjCPlugin;
346 | productReference = 1DC323C80F3B77990011E197 /* ExampleObjCPlugin.bundle */;
347 | productType = "com.apple.product-type.bundle";
348 | };
349 | 8D1107260486CEB800E47090 /* ExampleApplication */ = {
350 | isa = PBXNativeTarget;
351 | buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "ExampleApplication" */;
352 | buildPhases = (
353 | 8D1107290486CEB800E47090 /* Resources */,
354 | 8D11072C0486CEB800E47090 /* Sources */,
355 | 8D11072E0486CEB800E47090 /* Frameworks */,
356 | 1DC323DE0F3B78CE0011E197 /* Copy plugins */,
357 | );
358 | buildRules = (
359 | );
360 | dependencies = (
361 | 1DC323D90F3B78950011E197 /* PBXTargetDependency */,
362 | );
363 | name = ExampleApplication;
364 | productInstallPath = "$(HOME)/Applications";
365 | productName = ExampleApplication;
366 | productReference = 8D1107320486CEB800E47090 /* ExampleApplication.app */;
367 | productType = "com.apple.product-type.application";
368 | };
369 | /* End PBXNativeTarget section */
370 |
371 | /* Begin PBXProject section */
372 | 29B97313FDCFA39411CA2CEA /* Project object */ = {
373 | isa = PBXProject;
374 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ExampleApplication" */;
375 | compatibilityVersion = "Xcode 3.1";
376 | hasScannedForEncodings = 1;
377 | mainGroup = 29B97314FDCFA39411CA2CEA /* ExampleApplication */;
378 | projectDirPath = "";
379 | projectRoot = "";
380 | targets = (
381 | 8D1107260486CEB800E47090 /* ExampleApplication */,
382 | 1DC323C70F3B77990011E197 /* ExampleObjCPlugin */,
383 | );
384 | };
385 | /* End PBXProject section */
386 |
387 | /* Begin PBXResourcesBuildPhase section */
388 | 1DC323C40F3B77990011E197 /* Resources */ = {
389 | isa = PBXResourcesBuildPhase;
390 | buildActionMask = 2147483647;
391 | files = (
392 | );
393 | runOnlyForDeploymentPostprocessing = 0;
394 | };
395 | 8D1107290486CEB800E47090 /* Resources */ = {
396 | isa = PBXResourcesBuildPhase;
397 | buildActionMask = 2147483647;
398 | files = (
399 | 8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */,
400 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
401 | 1DC324320F3B89D30011E197 /* ExampleApplication.sdef in Resources */,
402 | 1DF38DEB0F3E205F00431004 /* Example.pl in Resources */,
403 | );
404 | runOnlyForDeploymentPostprocessing = 0;
405 | };
406 | /* End PBXResourcesBuildPhase section */
407 |
408 | /* Begin PBXSourcesBuildPhase section */
409 | 1DC323C50F3B77990011E197 /* Sources */ = {
410 | isa = PBXSourcesBuildPhase;
411 | buildActionMask = 2147483647;
412 | files = (
413 | 1DC323D20F3B77D80011E197 /* ExamplePlugin.m in Sources */,
414 | );
415 | runOnlyForDeploymentPostprocessing = 0;
416 | };
417 | 8D11072C0486CEB800E47090 /* Sources */ = {
418 | isa = PBXSourcesBuildPhase;
419 | buildActionMask = 2147483647;
420 | files = (
421 | 8D11072D0486CEB800E47090 /* main.m in Sources */,
422 | 1DC323110F3B74FA0011E197 /* PluginManager.m in Sources */,
423 | 1DC323D30F3B77DB0011E197 /* ExamplePlugin.m in Sources */,
424 | 1DC323EC0F3B795E0011E197 /* ExampleController.m in Sources */,
425 | 1DD73C610F3CFA9F00552B38 /* NSApplication+Applescript.m in Sources */,
426 | 1DF38D770F3DE9AA00431004 /* RubyPluginManager.m in Sources */,
427 | 1D9787B30F5F06780093EA87 /* FScriptPlugInManager.m in Sources */,
428 | 1D9787B40F5F06790093EA87 /* ApplescriptPluginManager.m in Sources */,
429 | 1D9787B50F5F067A0093EA87 /* JavascriptPluginManager.m in Sources */,
430 | 1D9787B60F5F067A0093EA87 /* LuaPluginManager.m in Sources */,
431 | 1D9787B70F5F067B0093EA87 /* NSApplescript+FCSAdditions.m in Sources */,
432 | 1D9787B80F5F067C0093EA87 /* NuPluginManager.m in Sources */,
433 | 1D9787B90F5F067D0093EA87 /* ObjCPluginManager.m in Sources */,
434 | 1D9787BB0F5F067F0093EA87 /* PythonPluginManager.m in Sources */,
435 | );
436 | runOnlyForDeploymentPostprocessing = 0;
437 | };
438 | /* End PBXSourcesBuildPhase section */
439 |
440 | /* Begin PBXTargetDependency section */
441 | 1DC323D90F3B78950011E197 /* PBXTargetDependency */ = {
442 | isa = PBXTargetDependency;
443 | target = 1DC323C70F3B77990011E197 /* ExampleObjCPlugin */;
444 | targetProxy = 1DC323D80F3B78950011E197 /* PBXContainerItemProxy */;
445 | };
446 | /* End PBXTargetDependency section */
447 |
448 | /* Begin PBXVariantGroup section */
449 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
450 | isa = PBXVariantGroup;
451 | children = (
452 | 089C165DFE840E0CC02AAC07 /* English */,
453 | );
454 | name = InfoPlist.strings;
455 | sourceTree = "";
456 | };
457 | 29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = {
458 | isa = PBXVariantGroup;
459 | children = (
460 | 29B97319FDCFA39411CA2CEA /* English */,
461 | );
462 | name = MainMenu.nib;
463 | sourceTree = "";
464 | };
465 | /* End PBXVariantGroup section */
466 |
467 | /* Begin XCBuildConfiguration section */
468 | 1DC323CB0F3B779C0011E197 /* Debug */ = {
469 | isa = XCBuildConfiguration;
470 | buildSettings = {
471 | ALWAYS_SEARCH_USER_PATHS = NO;
472 | ARCHS = "$(ARCHS_STANDARD_32_BIT)";
473 | COPY_PHASE_STRIP = NO;
474 | GCC_DYNAMIC_NO_PIC = NO;
475 | GCC_ENABLE_FIX_AND_CONTINUE = YES;
476 | GCC_ENABLE_OBJC_GC = supported;
477 | GCC_MODEL_TUNING = G5;
478 | GCC_OPTIMIZATION_LEVEL = 0;
479 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
480 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
481 | INFOPLIST_FILE = "ExampleObjCPlugin-Info.plist";
482 | INSTALL_PATH = "$(HOME)/Library/Bundles";
483 | OTHER_LDFLAGS = (
484 | "-framework",
485 | Foundation,
486 | "-framework",
487 | AppKit,
488 | );
489 | PREBINDING = NO;
490 | PRODUCT_NAME = ExampleObjCPlugin;
491 | WRAPPER_EXTENSION = bundle;
492 | };
493 | name = Debug;
494 | };
495 | 1DC323CC0F3B779C0011E197 /* Release */ = {
496 | isa = XCBuildConfiguration;
497 | buildSettings = {
498 | ALWAYS_SEARCH_USER_PATHS = NO;
499 | ARCHS = "$(ARCHS_STANDARD_32_BIT)";
500 | COPY_PHASE_STRIP = YES;
501 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
502 | GCC_ENABLE_FIX_AND_CONTINUE = NO;
503 | GCC_ENABLE_OBJC_GC = supported;
504 | GCC_MODEL_TUNING = G5;
505 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
506 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
507 | INFOPLIST_FILE = "ExampleObjCPlugin-Info.plist";
508 | INSTALL_PATH = "$(HOME)/Library/Bundles";
509 | OTHER_LDFLAGS = (
510 | "-framework",
511 | Foundation,
512 | "-framework",
513 | AppKit,
514 | );
515 | PREBINDING = NO;
516 | PRODUCT_NAME = ExampleObjCPlugin;
517 | WRAPPER_EXTENSION = bundle;
518 | ZERO_LINK = NO;
519 | };
520 | name = Release;
521 | };
522 | C01FCF4B08A954540054247B /* Debug */ = {
523 | isa = XCBuildConfiguration;
524 | buildSettings = {
525 | ALWAYS_SEARCH_USER_PATHS = NO;
526 | COPY_PHASE_STRIP = NO;
527 | FRAMEWORK_SEARCH_PATHS = (
528 | "$(inherited)",
529 | "\"$(SRCROOT)/../../../Programming examples/luacore/build/Release\"",
530 | );
531 | GCC_DYNAMIC_NO_PIC = NO;
532 | GCC_ENABLE_FIX_AND_CONTINUE = YES;
533 | GCC_ENABLE_OBJC_GC = supported;
534 | GCC_MODEL_TUNING = G5;
535 | GCC_OPTIMIZATION_LEVEL = 0;
536 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
537 | GCC_PREFIX_HEADER = ExampleApplication_Prefix.pch;
538 | INFOPLIST_FILE = Info.plist;
539 | INSTALL_PATH = "$(HOME)/Applications";
540 | LIBRARY_SEARCH_PATHS = (
541 | "$(inherited)",
542 | "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/Ruby.framework/Versions/1.8/usr/lib\"",
543 | );
544 | PRODUCT_NAME = ExampleApplication;
545 | };
546 | name = Debug;
547 | };
548 | C01FCF4C08A954540054247B /* Release */ = {
549 | isa = XCBuildConfiguration;
550 | buildSettings = {
551 | ALWAYS_SEARCH_USER_PATHS = NO;
552 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
553 | FRAMEWORK_SEARCH_PATHS = (
554 | "$(inherited)",
555 | "\"$(SRCROOT)/../../../Programming examples/luacore/build/Release\"",
556 | );
557 | GCC_ENABLE_OBJC_GC = supported;
558 | GCC_MODEL_TUNING = G5;
559 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
560 | GCC_PREFIX_HEADER = ExampleApplication_Prefix.pch;
561 | INFOPLIST_FILE = Info.plist;
562 | INSTALL_PATH = "$(HOME)/Applications";
563 | LIBRARY_SEARCH_PATHS = (
564 | "$(inherited)",
565 | "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/Ruby.framework/Versions/1.8/usr/lib\"",
566 | );
567 | PRODUCT_NAME = ExampleApplication;
568 | };
569 | name = Release;
570 | };
571 | C01FCF4F08A954540054247B /* Debug */ = {
572 | isa = XCBuildConfiguration;
573 | buildSettings = {
574 | ALWAYS_SEARCH_USER_PATHS = NO;
575 | ARCHS = "$(ARCHS_STANDARD_32_BIT)";
576 | GCC_OPTIMIZATION_LEVEL = 0;
577 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
578 | GCC_WARN_UNUSED_VARIABLE = YES;
579 | ONLY_ACTIVE_ARCH = YES;
580 | PREBINDING = NO;
581 | SDKROOT = macosx10.5;
582 | };
583 | name = Debug;
584 | };
585 | C01FCF5008A954540054247B /* Release */ = {
586 | isa = XCBuildConfiguration;
587 | buildSettings = {
588 | ALWAYS_SEARCH_USER_PATHS = NO;
589 | ARCHS = "$(ARCHS_STANDARD_32_BIT)";
590 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
591 | GCC_WARN_UNUSED_VARIABLE = YES;
592 | PREBINDING = NO;
593 | SDKROOT = macosx10.5;
594 | };
595 | name = Release;
596 | };
597 | /* End XCBuildConfiguration section */
598 |
599 | /* Begin XCConfigurationList section */
600 | 1DC323CD0F3B779C0011E197 /* Build configuration list for PBXNativeTarget "ExampleObjCPlugin" */ = {
601 | isa = XCConfigurationList;
602 | buildConfigurations = (
603 | 1DC323CB0F3B779C0011E197 /* Debug */,
604 | 1DC323CC0F3B779C0011E197 /* Release */,
605 | );
606 | defaultConfigurationIsVisible = 0;
607 | defaultConfigurationName = Release;
608 | };
609 | C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "ExampleApplication" */ = {
610 | isa = XCConfigurationList;
611 | buildConfigurations = (
612 | C01FCF4B08A954540054247B /* Debug */,
613 | C01FCF4C08A954540054247B /* Release */,
614 | );
615 | defaultConfigurationIsVisible = 0;
616 | defaultConfigurationName = Release;
617 | };
618 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ExampleApplication" */ = {
619 | isa = XCConfigurationList;
620 | buildConfigurations = (
621 | C01FCF4F08A954540054247B /* Debug */,
622 | C01FCF5008A954540054247B /* Release */,
623 | );
624 | defaultConfigurationIsVisible = 0;
625 | defaultConfigurationName = Release;
626 | };
627 | /* End XCConfigurationList section */
628 | };
629 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
630 | }
631 |
--------------------------------------------------------------------------------
/ExampleApplication/ExampleApplication_Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'ExampleApplication' target in the 'ExampleApplication' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #import
7 | #endif
8 |
--------------------------------------------------------------------------------
/ExampleApplication/ExampleController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleController.h
3 | // ExampleApplication
4 | //
5 | // Created by Grayson Hansard on 2/5/09.
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 |
13 | @interface ExampleController : NSObject {
14 | NSDictionary *_me;
15 | }
16 |
17 | @property (retain) NSDictionary *me;
18 |
19 | - (IBAction)showPluginMenu:(id)sender;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ExampleApplication/ExampleController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleController.m
3 | // ExampleApplication
4 | //
5 | // Created by Grayson Hansard on 2/5/09.
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "ExampleController.h"
10 | #import "PluginManager.h"
11 |
12 | @implementation ExampleController
13 |
14 | @synthesize me = _me;
15 |
16 | - (void)awakeFromNib
17 | {
18 | ABAddressBook *book = [ABAddressBook sharedAddressBook];
19 | ABPerson *me = [book me];
20 | ABMultiValue *mv = [me valueForProperty:kABPhoneProperty];
21 | NSMutableArray *array = [NSMutableArray array];
22 | unsigned int count = [mv count];
23 | unsigned int idx = 0;
24 | for (idx = 0; idx < count; idx++) [array addObject:[mv valueAtIndex:idx]];
25 | NSDictionary *meDict = [NSDictionary dictionaryWithObjectsAndKeys:
26 | [NSString stringWithFormat:@"%@ %@", [me valueForProperty:kABFirstNameProperty], [me valueForProperty:kABLastNameProperty], nil], @"name",
27 | array, @"phone", nil];
28 | self.me = meDict;
29 |
30 | [PluginManager pluginsForProperty:@"label-click" forValue:self.me withValue:@"with"];
31 | }
32 |
33 | - (IBAction)showPluginMenu:(id)sender {
34 | id value = nil;
35 | if ([sender tag] == 0) value = [self.me objectForKey:@"name"];
36 | else if ([sender tag] == 1) value = [self.me objectForKey:@"phone"];
37 | NSArray *plugins = [PluginManager pluginsForProperty:@"label-click" forValue:self.me withValue:value];
38 |
39 | NSMenu *m = [[[NSMenu alloc] initWithTitle:@"pluginMenu"] autorelease];
40 | for (NSDictionary *plugin in plugins) {
41 | NSDictionary *pluginDict = [NSDictionary dictionaryWithObjectsAndKeys:
42 | plugin, @"plugin",
43 | value, @"value", nil];
44 | NSMenuItem *mi = [m addItemWithTitle:[plugin objectForKey:@"title"] action:@selector(performPlugin:) keyEquivalent:@""];
45 | [mi setRepresentedObject:pluginDict];
46 | [mi setTarget:self];
47 | }
48 | [NSMenu popUpContextMenu:m withEvent:[NSApp currentEvent] forView:sender];
49 | }
50 |
51 | - (IBAction)performPlugin:(id)sender {
52 | NSDictionary *pluginDict = [sender representedObject];
53 | [PluginManager runPlugin:[pluginDict objectForKey:@"plugin"] forValue:self.me withValue:[pluginDict objectForKey:@"value"]];
54 | }
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/ExampleApplication/ExampleObjCPlugin-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.fcs.ExampleObjCPlugin
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleSignature
16 | ????
17 | CFBundleVersion
18 | 1.0
19 | NSPrincipalClass
20 | ExamplePlugin
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ExampleApplication/ExamplePlugin.h:
--------------------------------------------------------------------------------
1 | //
2 | // ExamplePlugin.h
3 | // ExampleApplication
4 | //
5 | // Created by Grayson Hansard on 2/5/09.
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ObjCPluginManager.h"
11 |
12 | @interface ExamplePlugin : NSObject {
13 |
14 | }
15 |
16 | -(NSString *)actionProperty;
17 | -(BOOL)actionEnableForValue:(id)forValue withValue:(id)withValue;
18 | -(NSString *)actionTitleForValue:(id)forValue withValue:(id)withValue;
19 | -(void)actionPerformForValue:(id)forValue withValue:(id)withValue;
20 | -(id)run;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ExampleApplication/ExamplePlugin.m:
--------------------------------------------------------------------------------
1 | //
2 | // ExamplePlugin.m
3 | // ExampleApplication
4 | //
5 | // Created by Grayson Hansard on 2/5/09.
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "ExamplePlugin.h"
10 |
11 |
12 | @implementation ExamplePlugin
13 |
14 | -(NSString *)actionProperty { return @"label-click"; }
15 | -(BOOL)actionEnableForValue:(id)forValue withValue:(id)withValue { return YES; }
16 | -(NSString *)actionTitleForValue:(id)forValue withValue:(id)withValue { return @"Perform ObjC Example plugin";}
17 | -(void)actionPerformForValue:(id)forValue withValue:(id)withValue {
18 | NSLog(@"%s", _cmd);
19 | }
20 | -(id)run {
21 | NSLog(@"%s", _cmd);
22 | return nil;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/ExampleApplication/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | com.fcs.ExampleApplication
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleSignature
20 | exPM
21 | CFBundleVersion
22 | 1.0
23 | NSAppleScriptEnabled
24 | YES
25 | NSMainNibFile
26 | MainMenu
27 | NSPrincipalClass
28 | NSApplication
29 | OSAScriptingDefinition
30 | ExampleApplication.sdef
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ExampleApplication/NSApplication+Applescript.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSApplication+Applescript.h
3 | // ExampleApplication
4 | //
5 | // Created by Grayson Hansard on 2/6/09.
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "PluginManager.h"
11 |
12 | @interface NSApplication (Applescript)
13 |
14 | - (id)ASRunScript:(NSScriptCommand *)aScriptCommand;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/ExampleApplication/NSApplication+Applescript.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSApplication+Applescript.m
3 | // ExampleApplication
4 | //
5 | // Created by Grayson Hansard on 2/6/09.
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "NSApplication+Applescript.h"
10 |
11 |
12 | @implementation NSApplication (Applescript)
13 |
14 | - (id)ASRunScript:(NSScriptCommand *)aScriptCommand {
15 | NSString *path = [aScriptCommand directParameter];
16 | return [PluginManager runScriptAtPath:path];
17 | }
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ExampleApplication/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ExampleApplication
4 | //
5 | // Created by Grayson Hansard on 2/5/09.
6 | // Copyright From Concentrate Software 2009. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | return NSApplicationMain(argc, (const char **) argv);
14 | }
15 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # The PluginManager
2 |
3 | I really like scriptable applications. I especially like applications that provide a plugin architecture. I am ecstatic to find applications that provide script-based plugins. Let's face it, writing a Cocoa bundle is kind of a pain in the ass even when using Python or Ruby. Being able to read plain text files as plugins is not only convenient, but it drastically lowers the barrier to entry for writing plugins (no dealing with Xcode).
4 |
5 | Unfortunately, very few applications provide this feature. The PluginManager attempts to resolve this issue. It's a series of classes that provides support for a vast number of scripting languages as well as standard Cocoa bundles. It is designed based on AddressBook's applescript plugin support but can be used in a wide number of ways. If nothing else, this project should provide an example into calling of scripts that you can adapt to your own applications.
6 |
7 | ## The Basic Design pattern
8 |
9 | There are two basic design patterns at work here. The first is the PluginManager pattern. The PluginManager can be accessed from the PluginManager with basic agnosticism to what scripts are running underneath. This is achieved by sub-managers registering themselves with the umbrella PluginManager. For example, in the NuPluginManager's `+load` method, it calls `[PluginManager registerManager:[[self new] autorelease]];` to add itself to the umbrella PluginManager's list of registered submanagers. All interactions should be done through this umbrella class.
10 |
11 | The second design pattern is in using the actual plugins. When a sub-manager loads, it generally finds all of the scripts that it can read and loads them into memory (perhaps inefficient, but the initial release was not coded for strict memory efficiency... this could change in future releases). Then, when the application calls `pluginsForProperty:forValue:withValue:`, it returns an NSArray of NSDictionaries which describes the plugin. At least one key will be relevant to the plugin (usually the actual plugin in memory), and one key will be `title` (as returned from the plugin's `actionTitle` function. Other keys may refer to information necessary for internal use by the plugin manager or to provide additional information about the plugin to the application. When the application is ready to run the plugin, it should call `runPlugin:forValue:withValue` and return the dictionary that was originally returned from `pluginsForProperty...`.
12 |
13 | As a third option, you can usually just call `runScriptAtPath:` to execute a script at a particular path. This won't work for Cocoa bundles at the moment, but I've got an idea or two.
14 |
15 | ## Please note the following
16 |
17 | At present, the plugin managers are not optimized for performance in any sense. They inherited a half-thought out design pattern and my first instinct was to just get them to work. I'll go back and make them more memory-efficient in the near future, but you should certain test for memory usage before shipping. Right now, I consider this code to be proof of concept rather than shipping quality.
18 |
19 | ## Todo
20 |
21 | A short list of things that I'll be trying to take care of relatively quickly.
22 |
23 | * Testing
24 | * Code commenting
25 | * Allow for dynamic loading of plugins based on user's installed 3rd party frameworks (useful so developers don't need to distribute the Nu framework, JSCocoa, or LuaCore in the application but can still offer that functionality for savvy users).
26 | * Write additional documentation describing the different plugins, language issues, and whatnot
27 |
28 | ## Necessary frameworks
29 |
30 | The Python, Ruby, Applescript, and Cocoa bundle submanagers only use frameworks that are instaled by default in OS X 10.5. The Javascript, Nu, Perl, and Lua submanagers require additional downloads. These frameworks can either be linked into the application or bundled with the app.
31 |
32 | * [Nu](http://programming.nu/) - Nu is a great, newish language by Tim Burks. I'm a big fan of Nu and have written several different components in it available on [Github](http://github.com/Grayson). You can download Nu [here](http://programming.nu/downloads).
33 |
34 | * [MacRuby](http://www.macruby.org/) - Sure, [RubyCocoa](http://rubycocoa.sourceforge.net/) is included with Mac OS X, but I got tired of fighting with it. MacRuby is a pain in a lot of ways, but it's less buggy and much easier to work with than RubyCocoa. I still wish I could have gotten RC to work, but if you want Ruby, you'll need to get MacRuby as well. Make sure to read the note below if using MacRuby.
35 |
36 | * [JSCocoa](http://inexdo.com/JSCocoa) - JSCocoa connects Cocoa to the JavascriptCore found in Webkit/Safari. It works wonders with easy integration in Objective-C applications. You can even use it as a framework or by compiling it directly into the code. It can be downloaded from its [Github page](http://github.com/parmanoir/jscocoa/tree/master).
37 |
38 | * [LuaCore](http://gusmueller.com/lua/) - Lua was one of my favorite plugin languages for a long time since it is so easily integrated with C. Although I've rolled my own code around the [LuaObjCBridge](http://luaforge.net/projects/luaobjcbridge/), I decided to go with Gus Mueller's LuaCore framework for this project. It can be downloaded from its [project page](http://gusmueller.com/lua/).
39 |
40 | * [CamelBones](http://camelbones.sourceforge.net/index.html) - CamelBones provides Perl support. However, I have to encourage lots of testing prior to using it. I had problems getting a version of CamelBones that worked on my Mac and I've heard that there are some problems based on which version of Perl you're using or which processor your Mac uses. Just the same, I'm assuming that if you have a version of CamelBones that works for you, the plugin manager will work as well. If you want Perl and Ruby support in the same application, make sure you read the note below on MacRuby.
41 |
42 | ## Contact information
43 |
44 | Patches, questions, comments, and any other communication can be sent via email to:
45 | Grayson Hansard
46 | [info@fromconcentratesoftware.com](mailto:info@fromconcentratesoftware)
47 |
48 | Patches, forks and other git stuff can be sent to PluginManager's github page at [http://github.com/Grayson/pluginmanager/](http://github.com/Grayson/pluginmanager/). However, I sometimes don't immediately notice pushes and whatnot so feel free to email me as well, especially if I don't incorporate or respond to changes in a day or two.
49 |
50 | Simple inquiries or comments can also be sent to [my Twitter account](http://twitter.com/Grayson): @Grayson.
51 |
52 | ## License information
53 |
54 | A lot of the frameworks that PluginManager relies upon have their own licenses. Make sure that if you bundle them with your application that you are following their license and giving credit where credit is due. As for PluginManager, I have not added a license at this time. I don't really feel the need but I would appreciate the following considerations:
55 |
56 | * If you fork or patch PluginManager, please send the changes on so that I can incorporate them. I'm happy to provide thanks for your work and it'd benefit the Mac programming community.
57 | * If you use PluginManager, please let me know. I like to see what applications are making use of the code and how it's working. I just like to visit my code and I'll provide a link in this readme that may move some random traffic your way (or at least increase your Google PageRank).
58 | * I also appreciate any remarks in a readme or About box, but that isn't necessary. I also won't turn down free software licenses. :)
59 |
60 | ## Special thanks
61 |
62 | I skimmed a lot of mailing lists and documentation to figure how to make some of this stuff work. Other times, I was fortunate enough to have direct access to the developers or other people with direct knowledge of how the necessary frameworks worked. And then there was stuff I just had to figure out on my own. I've tried to thank everyone that I could remember to thank, but if I forgot someone, I apologize.
63 |
64 | * [Tim Burks](http://blog.neontology.com/) - Mr. Burks is not only is the guy responsible for [Nu](http://programming.nu) but was also very helpful in helping me figure out how to interact with Nu.
65 | * [Gus Mueller](http://gusmueller.com) - Mr. Mueller compiled the LuaCore framework. Although I'm intimately familiar with Lua, I was happy to see that he had put together a lot of the work into providing an Objective-C frontend to Lua. I didn't want to compile a competing framework or increase the file noise with my own classes so I just extended his work a tiny bit (see LuaPluginManager.h). I also used the code on Mr. Mueller's [blog](http://gusmueller.com/blog/archives/2009/01/jscocoa_and_acorn_plugins_in_javascript.html) to help me get running with JSCocoa quickly.
66 | * [Patrick Geiller](http://parmanoir.com/) - Mr. Geiller created the JSCocoa package/framework. This was a massive boon in adding a Javascript plugin manager.
67 | * [Contributors to PyObjC](http://pyobjc.sourceforge.net/) - PyObjC is great. I love Python and PyObjC is magic. There were a few quirks that I had to work around, but once I got my head around it, PyObjC made everything else really easy.
68 | * [Contributors to RubyCocoa](http://rubycocoa.sourceforge.net/HomePage) - Like PyObjC, RubyCocoa is really easy to use and really lowered the barrier to entry in working with Ruby. I don't use Ruby and am rather unfamiliar with the language, but RubyCocoa was really easy to use and get working as I expected.
69 | * [Sherm Pendley](http://camelbones.sourceforge.net/) - CamelBones was a very early bridge and despite the fact that it often gets forgotten about, it's still pretty good. There's a lot of good work there and I'm not aware of any other Cocoa-Perl bridge. I sure wasn't about to write one so if you use PluginManager's Perl support, thank Mr. Pendley.
70 |
71 | ## A note about MacRuby
72 |
73 | I tried really hard to make RubyCocoa support work. I really did. But nothing seemed to go right. There were a ton of weird bugs and crashes that I got tired of trying to work around. I actually like RubyCocoa and would have preferred it to MacRuby for a few reasons (no garbage collection requirement, installed on OSX, better convenience methods), but I couldn't make it work. Maybe I'll return to it and try again in the future.
74 |
75 | However, I went with MacRuby. It has a lot going for it and it worked for me. Unfortunately, it has one rather sizeable issue: it require's Objective-C's new garbage collection. That may not sound like a bit deal, but it can be a problem if you're integrating plugins into a large codebase. You'll need to turn on garbage collection support (-fobjc-gc) for your project (which isn't too big of a deal), but you'll also need to make sure all of your frameworks, loadable bundles, and other stuff are also garbage collection-supported. For small projects, this may not be a big deal. For larger ones, this could be a deal breaker. Regardless, expect to see a lot of junk in the console when you turn on garbage collection and expect to crash until you update all of the compiled bits that your app depends on.
76 |
77 | For those of you who want to include Perl and Ruby in one project, I have bad news for you. I tried to find a way to compile CamelBones with garbage collection. As may be expected, that did *not* work very well. I haven't exactly racked my brain trying to figure this out, but I also don't really see many options here. This may be an instance where you have to pick one. Since CamelBones is kind of iffy anyway (you'll need to compile your own version for Leopard) and, perhaps, dying code, you may want to side with Ruby here. However, since Ruby support means turning on garbage collection support, it may be easier to just go with Perl. Again, I'll continue to evaluate RubyCocoa and incorporate it when possible.
78 |
79 | The Perl/Ruby problem also affects Python. With garbage collection turned in your application, you cannot import the objc module into your script. This means that custom objects can't cross the bridge. Sure, I've written some code to allow for the conversion of basic types, but your custom classes can't be used in scripts. This has something to do with the objc module. It was compiled without garbage collection turned on and therefore won't be loaded by the application if it has garbage collection support. Long story short, you can't use MacRuby and the default install of Python.
--------------------------------------------------------------------------------
/documentation/Applescript Plugin Example.markdown:
--------------------------------------------------------------------------------
1 | # About writing Applescript plugins
2 |
3 | Applescript is the best technology to absolutely frustrate hundreds upon hundreds (thousands upon thousands?) of Mac programmers. Let's face it, everyone seems to like it but no one wants to implement it. That's because it's hard and error-prone. Worse, the errors often don't tell the programmer much about what is going wrong. And often, something exceptionally minor can ruin someone's day.
4 |
5 | This example application has defined a small SDEF file that shows how to implement the same basic plugin architecture as Apple's Address Book.
6 |
7 | ## The necessary setup
8 |
9 | First and foremost, there's the sdef file. Note that you merely need to define the stuff that you want in the file as a command. You do not need to attach them to a class, but they need to be defined as a command. Next, you need to make sure that you have the appropriate keys set in the Info.plist file. You'll need NSAppleScriptEnabled set to YES and OSAScriptingDefinition set to the name of the sdef file (.sdef extension included). Finally, make sure that you've set a 4 char code in the "Creator" pane of the Properties tab of your application's Target Info.
10 |
11 | ## The rest should take care of itself
12 |
13 | If you've set up the sdef file as in the example (and you can copy it and just change the creator code and information although note that the commands also have the creator codes in them)
--------------------------------------------------------------------------------
/documentation/Nu support.markdown:
--------------------------------------------------------------------------------
1 | # How to embed Nu in Cocoa applications
2 |
3 | [Nu](http://programming.nu/) is a programming language built on top of Objective-C. It's a combination of Lisp syntax, Ruby idioms, and the Cocoa framework. Often, I find that it's very easy and efficient to prototype code in Nu and then port it to Objective-C when I need better performance. I'm a bit fan of Nu and really like using it whenever I can. Since Nu is dynamic and written on Objective-C, it was quick to embed.
4 |
5 | ## Getting started
6 |
7 | Like most of the other plugin managers, it's necessary to link in the appropriate framework. You can download Nu from its [download page](http://programming.nu/downloads). Simply download, install, and then link it to your Xcode project. Once that is done, simply add `#import ` to the top of your header file.
8 |
9 | ## Embedding Nu
10 |
11 | Nu provides a full featured parser, so it's really easy to implement. You just need to instantiate a parser, parse the code, and then run with it.
12 |
13 | id parser = [Nu parser];
14 | NSString *nuCode = [NSString stringWithContentsOfFile:nuFile];
15 | id returnedValue = [parser parseEval:nuCode];
16 | NSLog(@"%@", returnedValue);
17 |
18 | Let's say we have the following Nu script file:
19 |
20 | (function nuExample()
21 | "Hello, from Nu!")
22 |
23 | (function addMe(param1, param2)
24 | (+ param1 param2))
25 |
26 | There are two ways to call into Nu. I'll show the more direct method first and then show a more indirect method following. I personally prefer the indirect method as it doesn't throw any warnings or use any of Nu's non-public methods. However, this method is viable and nothing should go wrong if you use it. The first way is to retrieve the Nu function and then call it. Nu functions are [NuBlocks](http://programming.nu/doc/classes/NuBlock.html) and can be easily evaluated.
27 |
28 | id nuFunction = [parser valueForKey:@"nuExample"];
29 | NSLog(@"%@", [nuFunction evalWithArguments:nil context:[parser context]]);
30 |
31 | This should print "Hello, from Nu!" in the console. But, of course, we also want to be able to call functions with arguments. For this, we need to do a little bit of fudging with an NSArray. Nu's Lisp syntax likes NuCell lists. Before we toss arguments at it, we'll need to convert them into a Nu list. Luckily, Nu provides a method to NSArray that will handle this.
32 |
33 | id addMe = [parser valueForKey:@"addMe"];
34 | NSArray *args = [NSArray arrayWithObjects:[NSNumber numberWithInt:2], [NSNumber numberWithInt:3], nil];
35 | NSLog(@"%@", [addMe evalWithArguments:[args list] context:[parser context]]);
36 |
37 | This works and is rather direct, but the Nu framework does not make `evalWithArguments:context:` or NSArray's new `list` method known to the compiler. The headers for these aren't made public by the framework. Nothing should fail, but the compiler will complain a bit. You can stub out some categories that will define these methods or simply use `performSelector:` and its like in order to skirt these compiler warnings.
38 |
39 | ## An alternate method of calling into Nu
40 |
41 | If you're as lazy as I am about dealing with the compiler, there's another way. This way is less direct, but it avoids the compiler warnings and only uses what the Nu framework provides publicly. Basically, since Nu can evaluate code on the fly, you can call into Nu functions using Nu commands. Here's an example using the parser from above:
42 |
43 | NSLog(@"%@", [parser parseEval:@"(nuExample)"]);
44 |
45 | The parser knows about nuExample. All we are doing is telling it to call it using Nu. It's simple, easy, and doesn't require any minor hacks to work around the compiler. Of course, things get a bit hairier when calling functions with arguments. Since you're not calling it directly, you'll need to insert some additional information into the parser. You can inject global values into the parser using `setValue:forKey:` and then use those values when calling a function.
46 |
47 | // I'm using underscores in the name just to make sure that there aren't any other naming conflicts.
48 | [parser setValue:[NSNumber numberWithInt:2] forKey:@"__param1"];
49 | [parser setValue:[NSNumber numberWithInt:3] forKey:@"__param2"];
50 | NSLog(@"%@", [parser parseEval:@"(addMe __param1 __param2)"];
51 |
52 | What we're doing above is simply putting two NSNumbers into the parser's global context (called "`__param1`" and "`__param2`", respectively) and then using them when we call "`addMe`" from Nu. Nice and easy.
53 |
--------------------------------------------------------------------------------
/documentation/Perl support.markdown:
--------------------------------------------------------------------------------
1 | # CamelBones in 2009
2 |
3 | I really want to like CamelBones. And I do. It's a great piece of technology. But it hasn't been updated in a long time and it shows. If you download the latest version of CamelBones from the website, there's a rather high probability that it won't work for you. The one I downloaded didn't work for me. However, I fiddled with it until I got it to work. I'm going to post those instructions below as well as how to embed a Perl app using CamelBones. I do warn you that if it's this difficult to get a working version of CamelBones, you may consider avoiding Perl support since common users probably won't even apply. Or, perhaps, hosting a built version so they don't have to go through these steps.
4 |
5 | ## Building your own CamelBones
6 |
7 | When I downloaded CamelBones from its SourceForge page, the installer installed a framework that simply wouldn't load on my Intel-based Mac. Not being one to suffer this mild injustice, I downloaded the source package from SourceForge and tried building it. Well, the Xcode installer didn't work properly and make kept failing on me. Then I figured it out.
8 |
9 | 1. Download the source package from SourceForge. You'll need the files, after all.
10 | 2. Unarchive the source package and store it somewhere where there are no spaces or illegal characters in the path name. You'll avoid a small but annoying compiling bug with this one.
11 | 3. Open up Terminal.app and navigate to the source folder.
12 | 4. Run `./configure` in the Terminal. This creates the necessary files that Xcode will need when it does its stuff.
13 | 5. Open the xcode project and select the appropriate target. The appropriate target should be the nickname of your operating system. Since PluginManager uses ObjC 2.0 features at some places, go with "Leopard."
14 | 6. Build CamelBones using Xcode.
15 | 7. Navigate to the build/Release/ folder in the source folder and drag CamelBones.framework to /Library/Frameworks/.
16 | 8. There may be another step, but I'm not sure. The installer package probably installs a few other files that you may need to make sure everything works properly. If you figure this out, please let me know and I'll update these steps.
17 |
18 | ## Embedding Perl with CamelBones
19 |
20 | Sure, it's a bit of a hassle to install CamelBones, but it's a rather awesome technology so some of that can be forgiven by developers (for users that don't even know what Xcode is, it's probably still just a pain in the ass). First things first, import the CamelBones header.
21 |
22 | #import
23 |
24 | Now, the interpreter is really easy to use. It will eval code on the fly, so you just have to load it up.
25 |
26 | NSString *perlCode = [NSString stringWithContentsOfFile:filePath];
27 | CBPerl *perl = [CBPerl sharedPerl];
28 | NSLog(@"%@", [perl eval:perlCode]);
29 |
30 | ## Calling subroutines in Perl
31 |
32 | Unfortunately, although CamelBones provides lots of ways to retrieve objects, it doesn't let you retrieve subroutines. That's okay because we can use the same method that we used with Nu. You can inject objects into the Perl runtime and then call them by executing code on the fly.
33 |
34 | [perl setValue:@"example string" forKey:@"_exampleParameter"];
35 | [perl eval:@"doSomething($_exampleParameter);"];
36 |
37 | Note that Perl will still prefix variables with a "$", so don't forget about that. Also, since we're using CamelBones, you'll need to load it in the Perl file or else you'll experience some lovely crashes. The magic stuff is to simply put `use CamelBones qw(:All);` at the beginning of your Perl file. After that, you're ready to go.
--------------------------------------------------------------------------------
/documentation/Python support.markdown:
--------------------------------------------------------------------------------
1 | # How to embed Python in a Cocoa application
2 |
3 | Learning to call into Python was one of my biggest headaches when writing the PythonPluginManager. I wasn't able to find any example code other than simple embedding and PyObjC doesn't expose some of the more useful stuff to applications. There also isn't some nice Cocoa wrapper around Python like RubyCocoa provides for Ruby. However, by trial, error, and lots of swearing, it now appears to work.
4 |
5 | Embedding Python in a C application is actually fairly straightforward. Python itself provides several high-level functions that make it easier. To start, simply link the Python framework found at /System/Library/Frameworks/Python.framework into your application. Next, you'll want to import the Python header. From there, you can pretty much follow the [basic embedding instructions][embed] (note that I'm linking to the 2.6 docs simply because I prefer the page style; the instructions are basically the same for 2.5.x which ships with OS X).
6 |
7 | #import
8 | Py_Initialize();
9 | PyRun_SimpleString("print \"Hi, from Python.\"");
10 | Py_Finalize();
11 |
12 | [embed]: http://docs.python.org/extending/embedding.html
13 |
14 | ## Setup for better embedding
15 |
16 | The above example was nice, but quaint. There's not really a lot of work that can be done by using `PyRun_SimpleString`. You as well have just used NSTask. No, you'll want to really get into Python a bit deeper. You want to be able to run a file and then interact with it a bit. Right? First, you initialize Python with `Py_Initialize`, open the file as FILE* descriptor, get the main module and globals, and then run it using `PyRun_File`. In the example below, we haven't really used mainModule, but we will in the next section.
17 |
18 | Py_Initialize();
19 | Py_SetProgramName("/usr/bin/python");
20 | FILE *pyFile = fopen([pythonPath fileSystemRepresentation], "r");
21 |
22 | PyObject *mainModule = PyImport_AddModule("__main__");
23 | PyObject *globals = PyModule_GetDict(mainModule);
24 |
25 | PyRun_File(pyFile, [pythonPath UTF8String], Py_file_input, globals, globals);
26 |
27 | ## Now for something more entertaining
28 |
29 | Now that you've loaded a file using `PyRun_File` (or a similar high-level function), you can interact with it through its main module. Let's say that you wanted to call a function. Let's call this function "pythonExample" and make it have one parameter:
30 |
31 | # A python script
32 | def pythonExample(x):
33 | print x
34 | return "Nice to meet you!"
35 |
36 | Now, you can get the function as a PyObject using `PyObject_GetAttrString` on the main module:
37 |
38 | // Back into C/Objective-C/etc. now
39 | PyObject *pFunc = PyObject_GetAttrString(mainModule, "pythonExample");
40 |
41 | Note in the above that `PyObject_GetAttrString` expects a standard C string (char *) as its second parameter. Convert NSStrings as appropriate.
42 |
43 | Okay. You've got a function. You just need the arguments. Arguments are handled using a python tuple. Creating these in C is fairly simple.
44 |
45 | PyObject *tuple = PyTuple_New(1); // Only have 1 item in this tuple, if your function has more parameters, put the number of parameters in place of the 1
46 | PyObject *x = PyString_FromString("Hi, from Python"); // Turn a C string into a PyObject
47 | PyTuple_SetItem(tuple, 0, x); // Insert the PyObject into the tuple at index 0
48 |
49 | Now, you'll want to call this function. That's also fairly simple given the high level API provided by Python. However, on OS X, it's possible to get an unwaranted crash caused by the GIL state. This is easy to resolve:
50 |
51 | if (pFunc && PyCallable_Check(pFunc)) {
52 | PyGILState_STATE state = PyGILState_Ensure();
53 | PyObject *pValue = PyObject_CallObject(pFunc, tuple);
54 | Py_XDECREF(pFunc);
55 | PyGILState_Release(state);
56 | }
57 |
58 | If the function returned a value, it would be set in pValue. In the Python script above, we're returning a string ("Nice to meet you!") so pValue is a PyObject that represents that string.
59 |
60 | NSLog(@"%s", PyString_AsString(pValue));
61 |
62 | ## Putting it all together
63 |
64 | Here is another example of all of the steps above put together. However, I'm using a slightly different python method just to make sure that some of the concepts are demonstrated fully.
65 |
66 | # The new python script
67 | def anotherExample(param1, param2):
68 | return param1 * param2
69 |
70 | def anExampleWithNoParameters()
71 | return 42
72 |
73 |
74 | // Back to the C/Objective-C/etc. file
75 | // Assume pythonPath points to the python script above
76 | Py_Initialize();
77 | Py_SetProgramName("/usr/bin/python");
78 | FILE *pyFile = fopen([pythonPath fileSystemRepresentation], "r");
79 |
80 | PyObject *mainModule = PyImport_AddModule("__main__");
81 | PyObject *globals = PyModule_GetDict(mainModule);
82 |
83 | PyRun_File(pyFile, [pythonPath UTF8String], Py_file_input, globals, globals);
84 |
85 | // anotherExample() takes two parameters.
86 | PyObject *tuple = PyTuple_New(2);
87 | PyObject *param1 = PyInt_FromLong(5);
88 | PyObject *param2 = PyInt_FromLong(4);
89 | PyTuple_SetItem(tuple, 0, param1);
90 | PyTuple_SetItem(tuple, 1, param2);
91 |
92 | PyObject *pFunc = PyObject_GetAttrString(mainModule, "anotherExample");
93 | if (pFunc && PyCallable_Check(pFunc)) {
94 | PyGILState_STATE state = PyGILState_Ensure();
95 | PyObject *pValue = PyObject_CallObject(pFunc, tuple);
96 | Py_XDECREF(pFunc);
97 | PyGILState_Release(state);
98 | NSLog(@"%d", PyInt_AsLong(pValue));
99 | }
100 |
101 | ## Reusing the main module
102 |
103 | Okay, so you've called `anotherExample` above, but we also have `anExampleWithNoParameters`. What if you want to call it after you've called `anotherExample`? It's easy. Just hold on to the reference to mainModule and call it just like you normally would.
104 |
105 | PyObject *anotherFunc = PyObject_GetAttrString(mainModule, "anExampleWithNoParameters");
106 | if (pFunc && PyCallable_Check(anotherFunc)) {
107 | PyGILState_STATE state = PyGILState_Ensure();
108 | PyObject *pValue = PyObject_CallObject(anotherFunc, nil);
109 | Py_XDECREF(anotherFunc);
110 | PyGILState_Release(state);
111 | NSLog(@"%d", PyInt_AsLong(pValue));
112 | }
113 |
114 | Since there were no parameters, you can simply toss `nil` into `PyObject_CallObject` without worrying about creating another tuple. As long as you hold on to a valid reference to the main module, you can keep calling its functions in this manner. Of course, if you are going to call certain functions frequently, you can just hold on to those function references and call them more directly.
115 |
116 | ## A note about Py_Initialize()
117 |
118 | In all of these examples, I've shown `Py_Initialize()` as the first item to do. However, I read on some mailing lists that it is inefficient to call it multiple times in a program. Worse, it may have a memory leak in it (again, according to mailings lists). If you plan on running multiple files, you can simply call `Py_Initialize()` once early on then repeat the following steps for each file.
119 |
120 | If you plan on doing this, do not call `Py_Finalize()` until you are done using the Python interpreter. I haven't tried it yet, but I expect that if you call `Py_Finalize()` and then try to call Python functions and whatnot, bad things could happen. You should, of course, call `Py_Finalize()` when you are done with the interpreter, but if the Python interpreter will be running during the entire lifetime of the application, I don't suppose there's much harm in just forgetting about it and letting it get cleaned up with everything else when the user quits your app.
121 |
122 | ## Converting PyObjects into their Cocoa equivalents and vice versa
123 |
124 | PyObjC provides some nice functions that would convert PyObjects. I'd much prefer to actually use those methods, but unfortunately they don't seem to be provided to code outside of creating PyObjC modules. That's okay because it's fairly simple to convert basic classes (strings, numbers, dictionaries, arrays, etc.) into their Cocoa equivalents. PyObjC also wraps custom Cocoa classes in such a way as to make it easy to get to their values. Examples of this can be seen in PythonManagerPlugin.m. I won't repeat the code here, but take a look at the `pythonify` and `depythonify` functions at the top.
--------------------------------------------------------------------------------
/documentation/Ruby support.markdown:
--------------------------------------------------------------------------------
1 | # How to embed Ruby in Cocoa applications
2 |
3 | Ruby was easily the most difficult language I tried to get working in the PluginManager. However, most of that difficulty was from working with RubyCocoa. I want to say again that I like RubyCocoa and want to use it, but it simply wasn't built for embedding, especially with other languages. Getting full Ruby support meant going with [MacRuby](http://macruby.org).
4 |
5 | ## Getting started
6 |
7 | MacRuby is a complete Ruby system. There aren't any other requirements. You can simply drag the MacRuby framework into your application and link it. Well, you do that and turn on garbage collection. Simply open your app's target, switch to the "Build" tab, and search for "garbage". You then need to change the Objective-C Garbage Collection from "Unsupported" to "Supported" or "Required." Note that this may change your app's behavior, especially in regards to loading external bundles and frameworks. Once you've turned on GC, you can add the following to your header file:
8 |
9 | #import
10 |
11 | ## Ruby isn't hard
12 |
13 | MacRuby doesn't provide as useful convenience methods. There are some useful stuff, but not quite for what we want to do. If you use MacRuby's `evaluateFileAtPath:`, you won't receive the script object that we need to work with. For this, we'll have to delve into Ruby's embedding layer.
14 |
15 | [MacRuby sharedRuntime];
16 | VALUE script = rb_eval_string([[NSString stringWithContentsOfFile:scriptPath] UTF8String]);
17 |
18 | The first line simply starts the MacRuby runtime. You can receive a reference to the runtime and use some of MacRuby's convenience methods, but we're not doing that today. Today, we're calling into scripts. The second line simply uses rb\_eval_string (excuse the backslash if you're reading this in plain text), to evaluate the script. The script object is returned as a result.
19 |
20 | Let's assume that the ruby script just loaded was the following:
21 |
22 | def rubyExample
23 | return "Hi, from Ruby!"
24 | end
25 |
26 | def printMe (param1, param2)
27 | puts param1
28 | puts param2
29 | end
30 |
31 | We're going to need to use a bit more of the plain C embedding layer to call into these. First things first, calling a method is fairly easy. Ruby provides `rb_funcall`. It can be used in the following manner:
32 |
33 | VALUE ret = rb_funcall(script, rb_intern("rubyExample"), 0);
34 | NSLog(@"%@", RB2OC(ret));
35 |
36 | rb_funcall(script, rb_intern("printMe"), 2, OC2RB(@"this will be printed"), OC2RB(@"this is param2"));
37 |
38 | There are several `rb_funcall` functions. This is the basic one. The first parameter is the object that should be called. Since we're working with the script object from above, it'll be passed. The second parameter is Ruby's representation of the method, found using `rb_intern`. Note that we're using standard C strings (`char *`) and not NSStrings. The third parameter is the number of arguments to pass. In the case of no arguments, this will be the last parameter. However, if there are arguments, they'll simply be passed following this (as noted in the last line). Objects can be converted from Ruby using `RB2OC` and to Ruby using `OC2RB`.
39 |
40 | `rb_funcall` is great if you know exactly how many parameters you will pass (or otherwise like building var_arg lists). If you'd prefer a more convenient method, `rb_funcall2` may be appropriate. `rb_funcall2` works pretty much like `rb_funcall` except for it takes 4 arguments (instead of the variable number for `rb_funcall`) where the last argument is a C array of values that represent the arguments to pass to the script.
41 |
42 | VALUE args[2];
43 | args[0] = OC2RB(@"this will be printed");
44 | args[1] = OC2RB(@"this is param2");
45 | rb_funcall2(script, rb_intern("printMe"), 2, args);
46 | NSLog(@"%@", RB2OC( rb_funcall2(script, rb_intern("rubyExample"), 0, nil) ));
47 |
--------------------------------------------------------------------------------
/src/ApplescriptPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // ApplescriptPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "PluginManager.h"
11 | #import "PluginManagerProtocol.h"
12 | #import "NSApplescript+FCSAdditions.h"
13 | #import "PluginManagerApplescriptIncludes.h"
14 |
15 | @interface ApplescriptPluginManager : NSObject {
16 | NSMutableDictionary *_plugins;
17 | }
18 |
19 | @property (retain) NSMutableDictionary *plugins;
20 |
21 | -(NSString *)name;
22 | -(NSArray *)extensions;
23 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue;
24 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
25 | -(id)runScriptAtPath:(NSString *)path;
26 |
27 | @end
28 |
29 | unsigned long ASPluginAppClassCode();
--------------------------------------------------------------------------------
/src/ApplescriptPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // ApplescriptPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "ApplescriptPluginManager.h"
10 |
11 | @interface ApplescriptPluginManager (PrivateMethods)
12 | -(void)build;
13 | @end
14 |
15 | // Creates the 4-char code used by applescript to identify the application. This means the user does not have to
16 | // hard-code the app class code somewhere in the application.
17 | unsigned long ASPluginAppClassCode() {
18 | NSDictionary *infoPlist = [[NSBundle mainBundle] infoDictionary];
19 | NSString *sig = [infoPlist objectForKey:@"CFBundleSignature"];
20 | unsigned long code = 0;
21 | code += [sig characterAtIndex:0] << 24;
22 | code += [sig characterAtIndex:1] << 16;
23 | code += [sig characterAtIndex:2] << 8;
24 | code += [sig characterAtIndex:3];
25 | return code;
26 | }
27 |
28 | @implementation ApplescriptPluginManager
29 |
30 | @synthesize plugins = _plugins;
31 |
32 | +(void)load {
33 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
34 | [PluginManager registerManager:[[self new] autorelease]];
35 | [pool release];
36 | }
37 |
38 | -(id)init
39 | {
40 | self = [super init];
41 | if (!self) return nil;
42 |
43 | return self;
44 | }
45 |
46 | - (void)dealloc
47 | {
48 | self.plugins = nil;
49 | [super dealloc];
50 | }
51 |
52 | -(void)build
53 | {
54 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
55 | [self setPlugins:plugins];
56 |
57 | NSArray *foundPlugins = [PluginManager pluginFilesForSubmanager:self];
58 | NSAppleEventDescriptor *procDesc = [NSAppleScript processDescriptor];
59 | for (NSString *path in foundPlugins)
60 | {
61 | NSAppleScript *as = [NSAppleScript appleScriptWithContentsOfFile:path];
62 | if (!as) continue;
63 |
64 | NSAppleEventDescriptor *desc = [NSAppleEventDescriptor appleEventWithEventClass:ASPluginAppClassCode() eventID:ASPluginPropertyEventCode targetDescriptor:procDesc returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
65 | id err = nil;
66 | NSAppleEventDescriptor *ret = [as executeAppleEvent:desc error:&err];
67 | if (ret)
68 | {
69 | NSString *property = [ret stringValue];
70 | NSMutableArray *arr = [plugins objectForKey:property];
71 | if (!arr) arr = [NSMutableArray array];
72 | [arr addObject:as];
73 | [plugins setObject:arr forKey:property];
74 | }
75 | }
76 | }
77 |
78 | -(NSString *)name { return @"Applescript"; }
79 | -(NSArray *)extensions { return [NSArray arrayWithObject:@"scpt"]; }
80 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
81 | {
82 | if (![self plugins]) [self build];
83 | NSArray *arr = [[self plugins] objectForKey:property];
84 | if (!arr || ![arr count]) return nil;
85 |
86 | NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
87 | if (forValue) [parameters setObject:forValue forKey:[NSNumber numberWithUnsignedLong:ASPluginForCode]];
88 | if (withValue) [parameters setObject:withValue forKey:[NSNumber numberWithUnsignedLong:ASPluginWithCode]];
89 |
90 | NSEnumerator *e = [arr objectEnumerator];
91 | NSMutableArray *ret = [NSMutableArray array];
92 | NSAppleScript *as = nil;
93 |
94 | while (as = [e nextObject])
95 | {
96 | NSAppleEventDescriptor *enabledDesc = [as executeEvent:ASPluginEnableEventCode eventClass:ASPluginAppClassCode() parameters:parameters];
97 | if (enabledDesc && [enabledDesc booleanValue])
98 | {
99 | NSAppleEventDescriptor *desc = [as executeEvent:ASPluginTitleEventCode eventClass:ASPluginAppClassCode() parameters:parameters];
100 | if (desc)
101 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
102 | [desc stringValue], @"title",
103 | as, @"applescript",
104 | nil]];
105 | }
106 | }
107 | return ret;
108 | }
109 |
110 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
111 | {
112 | NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
113 | if (forValue) [parameters setObject:forValue forKey:[NSNumber numberWithUnsignedLong:ASPluginForCode]];
114 | if (withValue) [parameters setObject:withValue forKey:[NSNumber numberWithUnsignedLong:ASPluginWithCode]];
115 | [[plugin objectForKey:@"applescript"] executeEvent:ASPluginPerformEventCode eventClass:ASPluginAppClassCode() parameters:parameters];
116 | }
117 |
118 | -(id)runScriptAtPath:(NSString *)path
119 | {
120 | return [[NSAppleScript appleScriptWithContentsOfFile:path] executeAndReturnError:nil];
121 | }
122 |
123 | @end
124 |
--------------------------------------------------------------------------------
/src/FScriptPlugInManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // FScriptPlugInManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "PluginManager.h"
12 |
13 |
14 | @interface FScriptPlugInManager : NSObject {
15 | NSMutableDictionary *_plugins;
16 | }
17 |
18 | @property (retain) NSMutableDictionary *plugins;
19 |
20 | -(NSString *)name;
21 | -(NSArray *)extensions;
22 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)value;
23 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
24 | -(id)runScriptAtPath:(NSString *)path;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/src/FScriptPlugInManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // FScriptPlugInManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "FScriptPlugInManager.h"
10 |
11 |
12 | @implementation FScriptPlugInManager
13 |
14 | @synthesize plugins = _plugins;
15 |
16 | +(void)load {
17 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
18 | // Assume that the framework exists if strings can respond to `asBlock`.
19 | if ([@"" respondsToSelector:@selector(asBlock)])
20 | [PluginManager registerManager:[[self new] autorelease]];
21 | [pool release];
22 | }
23 |
24 | -(NSString *)name { return @"F-Script"; }
25 | -(NSArray *)extensions { return [NSArray arrayWithObjects:@"fs", @"fscript", nil]; }
26 |
27 | - (id)init
28 | {
29 | self = [super init];
30 | if (!self) return nil;
31 |
32 | return self;
33 | }
34 |
35 | - (void)dealloc
36 | {
37 | [self setPlugins:nil];
38 | [super dealloc];
39 | }
40 |
41 | - (void)build
42 | {
43 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
44 | self.plugins = plugins;
45 | for (NSString *path in [PluginManager pluginFilesForSubmanager:self])
46 | {
47 | FSInterpreter *interpreter = [FSInterpreter interpreter];
48 | NSString *fscriptCode = [NSString stringWithContentsOfFile:path];
49 |
50 | // Set up an FSInterpreter that will represent the plugin in memory. Load the code using `execute:`
51 | // and then get references to its functions using `objectForIdentifier:found:`.
52 | FSInterpreterResult *result = [interpreter execute:fscriptCode];
53 | if (![result isOK]) continue;
54 | BOOL found;
55 | FSBlock *b = [interpreter objectForIdentifier:@"actionProperty" found:&found];
56 | if (!found) continue;
57 | NSString *property = [b value];
58 | if (property && [property isKindOfClass:[NSString class]])
59 | {
60 | NSMutableArray *arr = [plugins objectForKey:property];
61 | if (!arr) arr = [NSMutableArray array];
62 | [arr addObject:interpreter];
63 | [plugins setObject:arr forKey:property];
64 | }
65 | }
66 | }
67 |
68 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
69 | {
70 | if (!self.plugins) [self build];
71 | NSArray *plugins = [self.plugins objectForKey:property];
72 | if (!plugins || ![plugins count]) return nil;
73 |
74 | NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
75 | FSInterpreter *interpreter = nil;
76 | NSMutableArray *ret = [NSMutableArray array];
77 | while (interpreter = [pluginEnumerator nextObject])
78 | {
79 | BOOL found = NO;
80 | FSBlock *b = [interpreter objectForIdentifier:@"actionEnable" found:&found];
81 | if (!found) continue;
82 |
83 | FSBoolean *isEnabled = [b value:forValue value:withValue];
84 | if (![isEnabled isKindOfClass:[True class]]) continue;
85 |
86 | b = [interpreter objectForIdentifier:@"actionTitle" found:&found];
87 | if (!found) continue;
88 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
89 | [b value:forValue value:withValue], @"title",
90 | interpreter, @"plugin",
91 | nil]];
92 | }
93 |
94 | return ret;
95 | }
96 |
97 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
98 | {
99 | FSInterpreter *interpreter = [plugin objectForKey:@"plugin"];
100 | BOOL found = NO;
101 | FSBlock *b = [interpreter objectForIdentifier:@"actionPerform" found:&found];
102 | if (!found) return;
103 | [b value:forValue value:withValue];
104 | }
105 |
106 | -(id)runScriptAtPath:(NSString *)path
107 | {
108 | NSString *fscriptCode = [NSString stringWithContentsOfFile:path];
109 | return [[fscriptCode asBlock] value];
110 | }
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/src/JavascriptPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "PluginManager.h"
12 | #import "PluginManagerProtocol.h"
13 |
14 |
15 | @interface JavascriptPluginManager : NSObject {
16 | NSMutableDictionary *_plugins;
17 | }
18 |
19 | @property (retain) NSMutableDictionary *plugins;
20 |
21 | -(NSString *)name;
22 | -(NSArray *)extensions;
23 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)value;
24 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
25 | -(id)runScriptAtPath:(NSString *)path;
26 |
27 | -(BOOL)canRunAsScript;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/src/JavascriptPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "JavascriptPluginManager.h"
10 |
11 |
12 | @implementation JavascriptPluginManager
13 |
14 | @synthesize plugins = _plugins;
15 |
16 | +(void)load {
17 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
18 | [PluginManager registerManager:[[self new] autorelease]];
19 | [pool release];
20 | }
21 |
22 | -(NSString *)name { return @"Javascript"; }
23 | -(NSArray *)extensions { return [NSArray arrayWithObjects:@"js", @"javascript", nil]; }
24 |
25 | - (id)init
26 | {
27 | self = [super init];
28 | if (!self) return nil;
29 |
30 | return self;
31 | }
32 |
33 | - (void)dealloc
34 | {
35 | self.plugins = nil;
36 | [super dealloc];
37 | }
38 |
39 | - (void)build
40 | {
41 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
42 | self.plugins = plugins;
43 |
44 | for (NSString *path in [PluginManager pluginFilesForSubmanager:self])
45 | {
46 | JSCocoaController *controller = [[JSCocoaController new] autorelease];
47 | [controller evalJSFile:path];
48 |
49 | if (![controller hasJSFunctionNamed:@"actionProperty"] ||
50 | ![controller hasJSFunctionNamed:@"actionEnable"] ||
51 | ![controller hasJSFunctionNamed:@"actionTitle"] ||
52 | ![controller hasJSFunctionNamed:@"actionPerform"]) continue;
53 |
54 | JSValueRef value = [controller callJSFunctionNamed:@"actionProperty" withArguments:nil];
55 | NSString *property;
56 | if (![JSCocoaFFIArgument unboxJSValueRef:value toObject:&property inContext:[controller ctx]]) continue;
57 |
58 | NSMutableArray *arr = [plugins objectForKey:property];
59 | if (!arr) arr = [NSMutableArray array];
60 | [arr addObject:controller];
61 | [plugins setObject:arr forKey:property];
62 | }
63 | }
64 |
65 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
66 | {
67 | if (!self.plugins) [self build];
68 | NSArray *plugins = [self.plugins objectForKey:property];
69 | if (!plugins || ![plugins count]) return nil;
70 |
71 | NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
72 | JSCocoaController *plugin;
73 | NSMutableArray *ret = [NSMutableArray array];
74 | while (plugin = [pluginEnumerator nextObject])
75 | {
76 | JSValueRef value = [plugin callJSFunctionNamed:@"actionEnable" withArguments:forValue, withValue, nil];
77 | NSNumber *shouldEnable = nil;
78 | if (![JSCocoaFFIArgument unboxJSValueRef:value toObject:&shouldEnable inContext:[plugin ctx]]) continue;
79 | if (shouldEnable && [shouldEnable boolValue])
80 | {
81 | JSValueRef titleRef = [plugin callJSFunctionNamed:@"actionTitle" withArguments:forValue, withValue, nil];
82 | NSString *title = nil;
83 | if (![JSCocoaFFIArgument unboxJSValueRef:titleRef toObject:&title inContext:[plugin ctx]]) continue;
84 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
85 | title, @"title",
86 | plugin, @"plugin",
87 | forValue, @"forValue",
88 | withValue, @"value",
89 | nil]];
90 | }
91 | }
92 |
93 | return ret;
94 | }
95 |
96 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
97 | {
98 | JSCocoaController *p = [plugin objectForKey:@"plugin"];
99 | [p callJSFunctionNamed:@"actionPerform" withArguments:forValue, withValue, nil];
100 | }
101 |
102 | -(id)runScriptAtPath:(NSString *)path
103 | {
104 | JSCocoaController *controller = [[JSCocoaController new] autorelease];
105 | JSValueRef valueRef;
106 | [controller evalJSFile:path toJSValueRef:&valueRef];
107 | id value = nil;
108 | if (![JSCocoaFFIArgument unboxJSValueRef:valueRef toObject:&value inContext:[controller ctx]]) return nil;
109 | return value;
110 | }
111 |
112 | -(BOOL)canRunAsScript { return YES; }
113 |
114 | @end
115 |
--------------------------------------------------------------------------------
/src/LuaPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "PluginManager.h"
12 |
13 |
14 | @interface LuaPluginManager : NSObject {
15 | NSMutableDictionary *_plugins;
16 | }
17 |
18 | @property (retain) NSMutableDictionary *plugins;
19 |
20 | -(NSString *)name;
21 | -(NSArray *)extensions;
22 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)value;
23 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
24 | -(id)runScriptAtPath:(NSString *)path;
25 |
26 | @end
27 |
28 | // These additions are made to LCLua.
29 | // They are simply convenience methods to retrieve return values from Lua functions.
30 | // These changes have been sent to Gus Mueller for review and addition to LCLua.
31 | // When they (or similar ones) are added, these methods can be removed.
32 | @interface LCLua (LuaPluginManagerAdditions)
33 | - (id)callEmptyFunctionNamed:(NSString *)functionName expectReturnValue:(BOOL)expect;
34 | - (id)callFunction:(NSString *)functionName expectReturnValue:(BOOL)expect arguments:(id)firstArg, ...;
35 | @end
36 |
--------------------------------------------------------------------------------
/src/LuaPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "LuaPluginManager.h"
10 |
11 |
12 | @implementation LuaPluginManager
13 |
14 | @synthesize plugins = _plugins;
15 |
16 | +(void)load {
17 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
18 | [PluginManager registerManager:[[self new] autorelease]];
19 | [pool release];
20 | }
21 |
22 | -(NSString *)name { return @"Lua"; }
23 | -(NSArray *)extensions { return [NSArray arrayWithObjects:@"lua", @"L", nil]; }
24 |
25 | - (id)init
26 | {
27 | self = [super init];
28 | if (!self) return nil;
29 |
30 | return self;
31 | }
32 |
33 | - (void)dealloc
34 | {
35 | self.plugins = nil;
36 | [super dealloc];
37 | }
38 |
39 | - (void)build
40 | {
41 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
42 | self.plugins = plugins;
43 | for (NSString *path in [PluginManager pluginFilesForSubmanager:self])
44 | {
45 | LCLua *lua = [LCLua readyLua];
46 | NSString *luaCode = [NSString stringWithContentsOfFile:path];
47 | [lua runFileAtPath:path];
48 |
49 | NSString *property = [lua callEmptyFunctionNamed:@"actionProperty" expectReturnValue:YES];
50 | NSMutableArray *arr = [plugins objectForKey:property];
51 | if (!arr) arr = [NSMutableArray array];
52 | [arr addObject:luaCode];
53 | [plugins setObject:arr forKey:property];
54 | }
55 | }
56 |
57 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
58 | {
59 | if (!self.plugins) [self build];
60 | NSArray *plugins = [self.plugins objectForKey:property];
61 | if (!plugins || ![plugins count]) return nil;
62 |
63 | NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
64 | id plugin;
65 | NSMutableArray *ret = [NSMutableArray array];
66 | withValue = withValue ? withValue : [NSNull null];
67 | forValue = forValue ? forValue : [NSNull null];
68 | while (plugin = [pluginEnumerator nextObject])
69 | {
70 | LCLua *lua = [LCLua readyLua];
71 | [lua runBuffer:plugin];
72 | if ([[lua callFunction:@"actionEnable" expectReturnValue:YES arguments:forValue, withValue, nil] boolValue])
73 | {
74 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
75 | [lua callFunction:@"actionTitle" expectReturnValue:YES arguments:forValue, withValue, nil], @"title",
76 | plugin, @"plugin",
77 | nil]];
78 | }
79 | }
80 |
81 | return ret;
82 | }
83 |
84 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
85 | {
86 | NSString *luaCode = [plugin objectForKey:@"plugin"];
87 | LCLua *lua = [LCLua readyLua];
88 | [lua runBuffer:luaCode];
89 | [lua callFunction:@"actionPerform" expectReturnValue:YES arguments:forValue, withValue, nil];
90 | }
91 |
92 | -(id)runScriptAtPath:(NSString *)path
93 | {
94 | LCLua *lua = [LCLua readyLua];
95 | [lua runFileAtPath:path];
96 | return nil;
97 | }
98 |
99 | @end
100 |
101 |
102 | @implementation LCLua (LuaPluginManagerAdditions)
103 | - (id)callEmptyFunctionNamed:(NSString *)functionName expectReturnValue:(BOOL)expect {
104 | // Push the function name onto the stack
105 | lua_pushstring (L, [functionName UTF8String]);
106 |
107 | // Function is located in the Global Table
108 | lua_gettable (L, LUA_GLOBALSINDEX);
109 |
110 | lua_pcall (L, 0, expect, 0);
111 | if (expect) {
112 | id ret = (id)lua_objc_topropertylist(L, -1);
113 | if (!ret) ret = (id)lua_objc_getid(L, -1);
114 | return ret;
115 | }
116 | return nil;
117 | }
118 |
119 | - (id)callFunction:(NSString *)functionName expectReturnValue:(BOOL)expect arguments:(id)firstArg, ... {
120 | int functionCount = 0;
121 |
122 | [[[NSThread currentThread] threadDictionary] setObject:[NSNumber numberWithBool:YES] forKey:@"LCRunningInLua"];
123 |
124 | lua_getglobal(L, [functionName UTF8String]);
125 |
126 | id eachArg;
127 | va_list argumentList;
128 | if (firstArg)
129 | {
130 | lua_objc_pushid(L, firstArg);
131 | functionCount++;
132 | va_start(argumentList, firstArg);
133 | while (eachArg = va_arg(argumentList, id)) {
134 | lua_objc_pushid(L, eachArg);
135 | functionCount++;
136 | }
137 | va_end(argumentList);
138 | }
139 |
140 | if (lua_pcall(L, functionCount, expect, 0) != 0) {
141 | NSLog(@"Error running function '%@': %s", functionName, lua_tostring(L, -1));
142 | }
143 |
144 | [[[NSThread currentThread] threadDictionary] removeObjectForKey:@"LCRunningInLua"];
145 | if (expect) {
146 | id ret = (id)lua_objc_topropertylist(L, -1);
147 | if (!ret) ret = (id)lua_objc_getid(L, -1);
148 | return ret;
149 | }
150 | return nil;
151 | }
152 | @end
--------------------------------------------------------------------------------
/src/NSApplescript+FCSAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSApplescript+FCSAdditions.h
3 | // FCSFramework
4 | //
5 | // Created by Grayson Hansard on 3/7/05.
6 | // Copyright 2005 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | NSAppleScript+FCSAdditions
13 | Additions that extends NSApplescript.
14 | */
15 | @interface NSAppleScript (FCSAdditions)
16 |
17 | /**
18 | A method that lets you call functions inside of applescripts.
19 | @param handler The function to call as a string.
20 | @param arguments The arguments sent to the function.
21 | @param errorInfo An NSDictionary pointer for error messages.
22 | @return Returns an NSAppleEventDescriptor.
23 | */
24 | - (NSAppleEventDescriptor *) callHandler: (NSString *) handler
25 | withArguments: (NSAppleEventDescriptor *) arguments
26 | errorInfo: (NSDictionary **) errorInfo;
27 |
28 | /**
29 | Convenience method for initializing an applescript from a file using a string path.
30 | @param path The path to a *.scpt file.
31 | @return Returns an NSAppleScript object.
32 | */
33 | -(NSAppleScript *)initWithContentsOfFile:(NSString *)path;
34 |
35 | /**
36 | Convenience method for getting an NSAppleScript from a file at a path.
37 | @param path The path to a *.scpt file.
38 | @return Returns an autoreleased NSAppleScript object.
39 | */
40 | +(NSAppleScript *)appleScriptWithContentsOfFile:(NSString *)path;
41 |
42 | -(NSAppleEventDescriptor *)executeEvent:(AEEventID)eventCode eventClass:(AEEventClass)eventClass parameters:(NSDictionary *)parameters;
43 |
44 | +(NSAppleEventDescriptor *)processDescriptor;
45 |
46 | +(BOOL)sendRecordableEventWithEventCode:(AEEventID)eventCode eventClass:(AEEventClass)eventClass
47 | directParameter:(id)directParam argumentsCodesAndValues:(id)firstCode, ...;
48 |
49 | @end
50 |
51 | @interface NSObject(HiddenMethods)
52 | - (NSAppleEventDescriptor *) _asDescriptor;
53 | @end
54 |
55 | @interface NSObject (ASPrivateMethods)
56 | -(NSAppleEventDescriptor *)ASDescriptor;
57 | @end
58 |
--------------------------------------------------------------------------------
/src/NSApplescript+FCSAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSApplescript+FCSAdditions.m
3 | // FCSFramework
4 | //
5 | // Created by Grayson Hansard on 3/7/05.
6 | // Copyright 2005 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "NSApplescript+FCSAdditions.h"
10 |
11 | @implementation NSAppleScript (FCSAdditions)
12 |
13 | - (NSAppleEventDescriptor *) callHandler: (NSString *) handler
14 | withArguments: (NSAppleEventDescriptor *) arguments
15 | errorInfo: (NSDictionary **) errorInfo
16 | {
17 | // Taken from Buzz Anderson, www.scifihifi.com
18 |
19 | NSAppleEventDescriptor* event;
20 | NSAppleEventDescriptor* targetAddress;
21 | NSAppleEventDescriptor* result;
22 |
23 | /* This will be a self-targeted AppleEvent, so we need to identify ourselves using our process id */
24 | int pid = [[NSProcessInfo processInfo] processIdentifier];
25 | targetAddress = [[NSAppleEventDescriptor alloc] initWithDescriptorType: typeKernelProcessID bytes: &pid length: sizeof(pid)];
26 |
27 | /* Set up our root AppleEvent descriptor: a subroutine call (psbr) */
28 | event = [[NSAppleEventDescriptor alloc] initWithEventClass: 'ascr' eventID: 'psbr' targetDescriptor: targetAddress returnID: kAutoGenerateReturnID transactionID: kAnyTransactionID];
29 |
30 | /* Set up an AppleEvent descriptor containing the subroutine (handler) name */
31 | [event setParamDescriptor:[NSAppleEventDescriptor descriptorWithString: [handler lowercaseString]] forKeyword: 'snam'];
32 |
33 | /* Add the provided arguments to the handler call */
34 | if (arguments) [event setParamDescriptor: arguments forKeyword: keyDirectObject];
35 |
36 | /* Execute the handler */
37 | result = [self executeAppleEvent: event error: errorInfo];
38 |
39 | [targetAddress release];
40 | [event release];
41 |
42 | return result;
43 | }
44 |
45 | -(NSAppleScript *)initWithContentsOfFile:(NSString *)path
46 | {
47 | self = [self initWithContentsOfURL:[NSURL fileURLWithPath:path] error:nil];
48 | return self;
49 | }
50 |
51 | +(NSAppleScript *)appleScriptWithContentsOfFile:(NSString *)path
52 | {
53 | return [[[NSAppleScript alloc] initWithContentsOfFile:path] autorelease];
54 | }
55 |
56 | -(NSAppleEventDescriptor *)executeEvent:(AEEventID)eventCode eventClass:(AEEventClass)eventClass parameters:(NSDictionary *)parameters
57 | {
58 | NSAppleEventDescriptor *procDesc = [NSAppleScript processDescriptor];
59 |
60 | NSAppleEventDescriptor *desc = [NSAppleEventDescriptor appleEventWithEventClass:eventClass eventID:eventCode targetDescriptor:procDesc returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
61 |
62 | NSEnumerator *e = [parameters keyEnumerator];
63 | NSNumber *key = nil;
64 | while (key = [e nextObject]) {
65 | [desc setParamDescriptor:[[parameters objectForKey:key] ASDescriptor] forKeyword:[key unsignedLongValue]];
66 | }
67 |
68 | NSDictionary *errorDict = nil;
69 | NSAppleEventDescriptor *returnDesc = [self executeAppleEvent:desc error:&errorDict];
70 | if (errorDict) NSLog(@"%@", errorDict);
71 | return returnDesc;
72 | }
73 |
74 | +(NSAppleEventDescriptor *)processDescriptor
75 | {
76 | ProcessSerialNumber selfPSN = {0, kCurrentProcess}; //using the PSN for the target is fastest
77 | return [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&selfPSN
78 | length:sizeof(ProcessSerialNumber)];
79 | }
80 |
81 | +(BOOL)sendRecordableEventWithEventCode:(AEEventID)eventCode eventClass:(AEEventClass)eventClass
82 | directParameter:(id)directParam argumentsCodesAndValues:(id)firstCode, ...
83 | {
84 | NSAppleEventDescriptor *procDesc = [NSAppleScript processDescriptor];
85 | NSAppleEventDescriptor *desc = [NSAppleEventDescriptor appleEventWithEventClass:eventClass
86 | eventID:eventCode
87 | targetDescriptor:procDesc
88 | returnID:kAutoGenerateReturnID
89 | transactionID:kAnyTransactionID];
90 |
91 | if (directParam) [desc setDescriptor:[directParam ASDescriptor] forKeyword:keyDirectObject];
92 |
93 | if (firstCode)
94 | {
95 | NSNumber *argCode = nil;
96 | id argValue = nil;
97 | va_list argList;
98 |
99 | argCode = firstCode;
100 | va_start(argList, firstCode);
101 | while (argValue = va_arg(argList, id))
102 | {
103 | [desc setParamDescriptor:[argValue ASDescriptor] forKeyword:[argCode unsignedLongValue]];
104 | argCode = va_arg(argList, NSNumber *);
105 | }
106 | va_end(argList);
107 | }
108 |
109 | AEDesc reply;
110 | OSErr err = AESend([desc aeDesc], &reply, kAENoReply | kAEDontExecute, kAENormalPriority,
111 | kAEDefaultTimeout, nil, nil);
112 | if (err != noErr) {
113 | NSLog(@"Error sending recordable AppleEvent.");
114 | NSLog(@"Reporting error #: %d", err);
115 | }
116 | return (err == noErr);
117 | }
118 |
119 | @end
120 |
121 | @implementation NSObject (ASPrivateMethods)
122 |
123 | // Convenience method used above to convert standard types (and types with object specifiers) into a suitable
124 | // descriptor.
125 | -(NSAppleEventDescriptor *)ASDescriptor
126 | {
127 | NSAppleEventDescriptor *desc = nil;
128 | if ([self isKindOfClass:[NSAppleEventDescriptor class]])
129 | desc = (NSAppleEventDescriptor *)self;
130 | else if ([self isKindOfClass:[NSString class]])
131 | desc = [NSAppleEventDescriptor descriptorWithString:(NSString *)self];
132 | else if ([self isKindOfClass:[NSNumber class]])
133 | desc = [NSAppleEventDescriptor descriptorWithInt32:[(NSNumber *)self intValue]];
134 | else if ([self isKindOfClass:[NSDictionary class]]) {
135 | desc = [NSAppleEventDescriptor recordDescriptor];
136 | NSMutableArray *items = [NSMutableArray array];
137 | for (NSString *key in [(NSDictionary *)self allKeys]) {
138 | [items addObject:key];
139 | [items addObject:[(NSDictionary *)self objectForKey:key]];
140 | }
141 | [desc setParamDescriptor:[items ASDescriptor] forKeyword:'usrf'];
142 | }
143 | else if ([self isKindOfClass:[NSArray class]]) {
144 | desc = [NSAppleEventDescriptor listDescriptor];
145 | unsigned int idx = 1;
146 | for (id obj in (NSArray *)self) [desc insertDescriptor:[obj ASDescriptor] atIndex:idx++];
147 | }
148 | else if ([self respondsToSelector:@selector(objectSpecifier)])
149 | desc = [[self objectSpecifier] _asDescriptor];
150 | else
151 | desc = [NSAppleEventDescriptor nullDescriptor];
152 | return desc ? desc : [NSAppleEventDescriptor nullDescriptor];
153 | }
154 |
155 | @end
156 |
--------------------------------------------------------------------------------
/src/NuPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "PluginManager.h"
12 |
13 |
14 | @interface NuPluginManager : NSObject {
15 | NSMutableDictionary *_plugins;
16 | }
17 |
18 | @property (retain) NSMutableDictionary *plugins;
19 |
20 | -(NSString *)name;
21 | -(NSArray *)extensions;
22 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)value;
23 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
24 | -(id)runScriptAtPath:(NSString *)path;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/src/NuPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "NuPluginManager.h"
10 |
11 |
12 | @implementation NuPluginManager
13 |
14 | @synthesize plugins = _plugins;
15 |
16 | +(void)load {
17 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
18 | if (NSClassFromString(@"Nu")) [PluginManager registerManager:[[self new] autorelease]];
19 | [pool release];
20 | }
21 |
22 | -(NSString *)name { return @"Nu"; }
23 | -(NSArray *)extensions { return [NSArray arrayWithObject:@"nu"]; }
24 |
25 | - (id)init
26 | {
27 | self = [super init];
28 | if (!self) return nil;
29 |
30 | return self;
31 | }
32 |
33 | - (void)dealloc
34 | {
35 | self.plugins = nil;
36 | [super dealloc];
37 | }
38 |
39 | - (void)build
40 | {
41 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
42 | self.plugins = plugins;
43 | for (NSString *path in [PluginManager pluginFilesForSubmanager:self])
44 | {
45 | id parser = [Nu parser];
46 | NSString *nuCode = [NSString stringWithContentsOfFile:path];
47 | [parser parseEval:nuCode];
48 | NSString *property = [parser parseEval:@"(actionProperty)"];
49 |
50 | NSMutableArray *arr = [plugins objectForKey:property];
51 | if (!arr) arr = [NSMutableArray array];
52 | [arr addObject:nuCode];
53 | [plugins setObject:arr forKey:property];
54 | [parser close];
55 | }
56 | }
57 |
58 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
59 | {
60 | if (!self.plugins) [self build];
61 | NSArray *plugins = [self.plugins objectForKey:property];
62 | if (!plugins || ![plugins count]) return nil;
63 |
64 | NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
65 | id plugin;
66 | NSMutableArray *ret = [NSMutableArray array];
67 | withValue = withValue ? withValue : [NSNull null];
68 | forValue = forValue ? forValue : [NSNull null];
69 | while (plugin = [pluginEnumerator nextObject])
70 | {
71 | id parser = [Nu parser];
72 | [parser parseEval:plugin];
73 | [parser setValue:forValue forKey:@"_pluginWithValue"];
74 | [parser setValue:withValue forKey:@"_pluginForValue"];
75 | if ([[parser parseEval:@"(actionEnable _pluginWithValue _pluginForValue)"] boolValue])
76 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
77 | [parser parseEval:@"(actionTitle _pluginWithValue _pluginForValue)"], @"title",
78 | plugin, @"plugin",
79 | nil]];
80 | [parser close];
81 | }
82 |
83 | return ret;
84 | }
85 |
86 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
87 | {
88 | withValue = withValue ? withValue : [NSNull null];
89 | forValue = forValue ? forValue : [NSNull null];
90 | NSString *nuCode = [plugin objectForKey:@"plugin"];
91 | id parser = [Nu parser];
92 | [parser parseEval:nuCode];
93 | [parser setValue:forValue forKey:@"_pluginWithValue"];
94 | [parser setValue:withValue forKey:@"_pluginForValue"];
95 | [parser parseEval:@"(actionPerform _pluginWithValue _pluginForValue)"];
96 | [parser close];
97 | }
98 |
99 | -(id)runScriptAtPath:(NSString *)path
100 | {
101 | id parser = [Nu parser];
102 | id ret = [parser parseEval:[NSString stringWithContentsOfFile:path]];
103 | [parser close];
104 | return ret;
105 | }
106 |
107 | @end
108 |
--------------------------------------------------------------------------------
/src/ObjCPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "PluginManager.h"
11 | #import "PluginManagerProtocol.h"
12 |
13 | enum {
14 | ObjCPMBundleLoadError = 1,
15 | ObjCPMClassLoadError = 2
16 | };
17 |
18 | @interface ObjCPluginManager : NSObject {
19 | NSMutableDictionary *_plugins;
20 | }
21 |
22 | @property (retain) NSMutableDictionary *plugins;
23 |
24 | -(NSString *)name;
25 | -(NSArray *)extensions;
26 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)value;
27 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
28 | -(id)runScriptAtPath:(NSString *)path;
29 |
30 | -(BOOL)canRunAsScript;
31 |
32 | @end
33 |
34 | @protocol ObjCPlugin
35 | -(NSString *)actionProperty;
36 | -(BOOL)actionEnableForValue:(id)forValue withValue:(id)withValue;
37 | -(NSString *)actionTitleForValue:(id)forValue withValue:(id)withValue;
38 | -(void)actionPerformForValue:(id)forValue withValue:(id)withValue;
39 | -(id)run;
40 | @end
41 |
--------------------------------------------------------------------------------
/src/ObjCPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "ObjCPluginManager.h"
10 |
11 |
12 | @implementation ObjCPluginManager
13 |
14 | @synthesize plugins = _plugins;
15 |
16 | +(void)load {
17 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
18 | [PluginManager registerManager:[[self new] autorelease]];
19 | [pool release];
20 | }
21 |
22 | -(NSString *)name { return @"Objective-C"; }
23 | -(NSArray *)extensions { return [NSArray arrayWithObject:@"bundle"]; }
24 |
25 | - (id)init
26 | {
27 | self = [super init];
28 | if (!self) return nil;
29 |
30 | return self;
31 | }
32 |
33 | - (void)dealloc
34 | {
35 | self.plugins = nil;
36 | [super dealloc];
37 | }
38 |
39 | - (void)build
40 | {
41 | NSMutableDictionary *plugins = [self plugins];
42 | if (!plugins) {
43 | plugins = [NSMutableDictionary dictionary];
44 | [self setPlugins:plugins];
45 | }
46 |
47 | NSArray *foundPlugins = [PluginManager pluginFilesForSubmanager:self];
48 | NSEnumerator *pluginEnumerator = [foundPlugins objectEnumerator];
49 | NSString *path;
50 | NSArray *extensions = [self extensions];
51 | while (path = [pluginEnumerator nextObject])
52 | {
53 | if (![extensions containsObject:[path pathExtension]]) continue;
54 |
55 | NSBundle *b = [NSBundle bundleWithPath:path];
56 | if (!b) continue;
57 |
58 | Class c = [b principalClass];
59 | if (![c conformsToProtocol:@protocol(ObjCPlugin)]) continue;
60 |
61 | id plugin = [c new];
62 | NSString *property = [plugin actionProperty];
63 | NSMutableArray *arr = [plugins objectForKey:property];
64 | if (!arr) arr = [NSMutableArray array];
65 | [arr addObject:plugin];
66 | [plugins setObject:arr forKey:property];
67 | }
68 | }
69 |
70 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
71 | {
72 | if (![self plugins]) [self build];
73 | NSArray *plugins = [[self plugins] objectForKey:property];
74 | if (!plugins || ![plugins count]) return nil;
75 |
76 | NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
77 | id plugin;
78 | NSMutableArray *ret = [NSMutableArray array];
79 | while (plugin = [pluginEnumerator nextObject])
80 | {
81 | if ([plugin actionEnableForValue:forValue withValue:withValue])
82 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
83 | [plugin actionTitleForValue:forValue withValue:withValue], @"title",
84 | plugin, @"plugin",
85 | forValue, @"forValue",
86 | withValue, @"value",
87 | nil]];
88 | }
89 |
90 | return ret;
91 | }
92 |
93 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
94 | {
95 | id p = [plugin objectForKey:@"plugin"];
96 | [p actionPerformForValue:forValue withValue:withValue];
97 | }
98 |
99 | -(id)runScriptAtPath:(NSString *)path
100 | {
101 | if (!path) return nil;
102 | NSMutableDictionary *plugins = [self plugins];
103 | if (!plugins) plugins = [NSMutableDictionary dictionary];
104 | id plugin = [plugins objectForKey:path];
105 | unsigned int errorCode = 0;
106 | NSString *errorString = nil;
107 | if (!plugin) {
108 | NSBundle *b = [NSBundle bundleWithPath:path];
109 | if (![b load]) {
110 | errorString = [NSString stringWithFormat:NSLocalizedString(@"File at path '%@' is not a valid bundle.", @"error message"), path];
111 | errorCode = ObjCPMBundleLoadError;
112 | goto error;
113 | }
114 | plugin = [[[b class] new] autorelease];
115 | if (!plugin) {
116 | errorString = [NSString stringWithFormat:NSLocalizedString(@"Could not load class from Cocoa bundle at path: %@", @"error message"), path];
117 | errorCode = ObjCPMClassLoadError;
118 | goto error;
119 | }
120 | if (![(id)plugin respondsToSelector:@selector(run)]) {
121 | errorString = [NSString stringWithFormat:NSLocalizedString(@"Loaded bundle at path '%@' does not respond to -(id)run.", @"error message"), path];
122 | errorCode = 3;
123 | goto error;
124 | }
125 | [plugins setObject:plugin forKey:path];
126 | }
127 |
128 | return [plugin run];
129 |
130 | // If a plugin can't be loaded and used, create an NSError and return it. I dislike using exceptions here
131 | // since plugins aren't really show stoppers and shouldn't stop an application to deal with them.
132 | error:;
133 | if (!errorString) return nil;
134 | NSDictionary *errorDict = [NSDictionary dictionaryWithObject:errorString forKey:NSLocalizedDescriptionKey];
135 | return [NSError errorWithDomain:@"com.fcs.objcpluginmanager" code:errorCode userInfo:errorDict];
136 | }
137 |
138 | -(BOOL)canRunAsScript { return YES; }
139 |
140 |
141 | @end
142 |
--------------------------------------------------------------------------------
/src/PerlPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // PerlPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "PluginManager.h"
12 |
13 |
14 | @interface PerlPluginManager : NSObject {
15 | NSMutableDictionary *_plugins;
16 | }
17 |
18 | @property (retain) NSMutableDictionary *plugins;
19 |
20 | -(NSString *)name;
21 | -(NSArray *)extensions;
22 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)value;
23 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
24 | -(id)runScriptAtPath:(NSString *)path;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/src/PerlPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // PerlPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "PerlPluginManager.h"
10 |
11 |
12 | @implementation PerlPluginManager
13 |
14 | @synthesize plugins = _plugins;
15 |
16 | +(void)load {
17 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
18 | if (NSClassFromString(@"CBPerl")) [PluginManager registerManager:[[self new] autorelease]];
19 | [pool release];
20 | }
21 |
22 | -(NSString *)name { return @"Perl"; }
23 | -(NSArray *)extensions { return [NSArray arrayWithObjects:@"pl", @"perl", nil]; }
24 |
25 | - (id)init
26 | {
27 | self = [super init];
28 | if (!self) return nil;
29 |
30 | return self;
31 | }
32 |
33 | - (void)dealloc
34 | {
35 | self.plugins = nil;
36 | [super dealloc];
37 | }
38 |
39 | - (void)build
40 | {
41 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
42 | self.plugins = plugins;
43 | for (NSString *path in [PluginManager pluginFilesForSubmanager:self])
44 | {
45 | CBPerl *perl = [CBPerl sharedPerl];
46 | NSString *perlCode = [NSString stringWithContentsOfFile:path];
47 | [perl eval:perlCode];
48 | NSString *property = [perl eval:@"actionProperty();"];
49 | if (!property) continue;
50 | NSMutableArray *arr = [plugins objectForKey:property];
51 | if (!arr) arr = [NSMutableArray array];
52 | [arr addObject:perlCode];
53 | [plugins setObject:arr forKey:property];
54 | }
55 | }
56 |
57 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
58 | {
59 | if (!self.plugins) [self build];
60 | NSArray *plugins = [self.plugins objectForKey:property];
61 | if (!plugins || ![plugins count]) return nil;
62 |
63 | NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
64 | NSString *perlCode = nil;
65 | NSMutableArray *ret = [NSMutableArray array];
66 | CBPerl *perl = [CBPerl sharedPerl];
67 | withValue = withValue ? withValue : [NSNull null];
68 | forValue = forValue ? forValue : [NSNull null];
69 | while (perlCode = [pluginEnumerator nextObject])
70 | {
71 | [perl eval:perlCode];
72 | [perl setValue:forValue forKey:@"_forValue"];
73 | [perl setValue:withValue forKey:@"_withValue"];
74 | if ([[perl eval:@"actionEnable($_forValue, $_withValue);"] boolValue]) {
75 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
76 | [perl eval:@"actionTitle($_forValue, $_withValue);"], @"title",
77 | perlCode, @"code", nil]];
78 | }
79 | }
80 |
81 | return ret;
82 | }
83 |
84 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
85 | {
86 | NSString *perlCode = [plugin objectForKey:@"code"];
87 | if (!perlCode) return;
88 | CBPerl *perl = [CBPerl sharedPerl];
89 | [perl eval:perlCode];
90 | [perl setValue:forValue ? forValue : [NSNull null] forKey:@"_forValue"];
91 | [perl setValue:withValue ? withValue : [NSNull null] forKey:@"_withValue"];
92 | [perl eval:@"actionPerform($_withValue, $_forValue);"];
93 | }
94 |
95 | -(id)runScriptAtPath:(NSString *)path
96 | {
97 | return [[CBPerl sharedPerl] eval:[NSString stringWithContentsOfFile:path]];
98 | }
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/src/PluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // PluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "PluginManagerProtocol.h"
12 |
13 | @interface PluginManager : NSObject {
14 | NSMutableArray *_pluginManagers;
15 | }
16 |
17 | +(id)manager;
18 | +(NSString *)pathToPluginsFolder;
19 | +(void)registerManager:(id)manager;
20 |
21 | +(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue;
22 | +(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
23 |
24 | +(BOOL)canRunFileWithExtension:(NSString *)ext;
25 | +(id)runScriptAtPath:(NSString *)path;
26 |
27 | +(NSArray *)managerInfo;
28 |
29 | +(NSArray *)pluginFilesForSubmanager:(id)submanager;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/src/PluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // PluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "PluginManager.h"
10 |
11 | @interface PluginManager (PrivateMethods)
12 | -(BOOL)canRunFileWithExtension:(NSString *)ext;
13 | -(id)runScriptAtPath:(NSString *)path;
14 | -(void)buildPluginsDictionary;
15 | -(void)loadPluginManagers;
16 | -(void)registerManager:(id)manager;
17 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue;
18 | -(NSArray *)managerInfo;
19 | @end
20 |
21 | static id _pluginManagerInstance = nil;
22 |
23 | @implementation PluginManager
24 |
25 | +(id)manager
26 | {
27 | if (!_pluginManagerInstance) _pluginManagerInstance = [[self class] new];
28 | return _pluginManagerInstance;
29 | }
30 |
31 | +(void)registerManager:(id)manager
32 | {
33 | [[PluginManager manager] registerManager:manager];
34 | }
35 |
36 | -(void)registerManager:(id)manager
37 | {
38 | if (![_pluginManagers containsObject:manager]) [_pluginManagers addObject:manager];
39 | }
40 |
41 | +(BOOL)canRunFileWithExtension:(NSString *)ext
42 | {
43 | return [[PluginManager manager] canRunFileWithExtension:ext];
44 | }
45 |
46 | -(BOOL)canRunFileWithExtension:(NSString *)ext
47 | {
48 | NSEnumerator *e = [[_pluginManagers valueForKeyPath:@"extensions"] objectEnumerator];
49 | NSArray *arr = nil;
50 | while (arr = [e nextObject]) if ([arr containsObject:ext]) return YES;
51 | return NO;
52 | }
53 |
54 | +(id)runScriptAtPath:(NSString *)path
55 | {
56 | return [[PluginManager manager] runScriptAtPath:path];
57 | }
58 |
59 | -(id)runScriptAtPath:(NSString *)path
60 | {
61 | NSEnumerator *e = [_pluginManagers objectEnumerator];
62 | id m = nil;
63 | NSString *ext = [path pathExtension];
64 | while (m = [e nextObject])
65 | {
66 | if ([[m extensions] containsObject:ext])
67 | return [m runScriptAtPath:path];
68 | }
69 | return nil;
70 | }
71 |
72 | -(id)init
73 | {
74 | self = [super init];
75 | if (!self) return nil;
76 |
77 | _pluginManagers = [NSMutableArray new];
78 | [self loadPluginManagers];
79 |
80 | return self;
81 | }
82 |
83 | -(void)dealloc
84 | {
85 | NSEnumerator *e = [_pluginManagers objectEnumerator];
86 | id m = nil;
87 | while (m = [e nextObject])
88 | {
89 | [_pluginManagers removeObject:m];
90 | [m release];
91 | }
92 |
93 | [_pluginManagers release];
94 | _pluginManagers = nil;
95 | [super dealloc];
96 | }
97 |
98 | +(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue;
99 | {
100 | return [[PluginManager manager] pluginsForProperty:property forValue:forValue withValue:withValue];
101 | }
102 |
103 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue;
104 | {
105 | NSMutableArray *plugins = [NSMutableArray array];
106 |
107 | NSEnumerator *e = [_pluginManagers objectEnumerator];
108 | id m = nil;
109 | while (m = [e nextObject])
110 | {
111 | NSMutableArray *arr = [NSMutableArray array];
112 | NSEnumerator *ee = [[m pluginsForProperty:property forValue:forValue withValue:withValue] objectEnumerator];
113 | NSDictionary *d = nil;
114 | while (d = [ee nextObject])
115 | {
116 | NSMutableDictionary *dd = [[d mutableCopy] autorelease];
117 | [dd setObject:m forKey:@"target_plugin"];
118 | [arr addObject:dd];
119 | }
120 | [plugins addObjectsFromArray:arr];
121 | }
122 |
123 | return plugins;
124 | }
125 |
126 | +(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
127 | {
128 | id p = [plugin objectForKey:@"target_plugin"];
129 | [p runPlugin:plugin forValue:forValue withValue:withValue];
130 | }
131 |
132 | +(NSArray *)managerInfo { return [[PluginManager manager] managerInfo]; }
133 | -(NSArray *)managerInfo
134 | {
135 | NSEnumerator *e = [_pluginManagers objectEnumerator];
136 | id p = nil;
137 | NSMutableArray *arr = [NSMutableArray array];
138 | while (p = [e nextObject])
139 | [arr addObject:[NSDictionary dictionaryWithObject:[p extensions] forKey:[p name]]];
140 | return arr;
141 | }
142 |
143 |
144 |
145 | #pragma mark -
146 | #pragma mark Private methods
147 |
148 | -(void)loadPluginManagers
149 | {
150 | NSFileManager *fm = [NSFileManager defaultManager];
151 | NSString *pluginsPath = [[self class] pathToPluginsFolder];
152 | NSArray *plugins = [fm directoryContentsAtPath:pluginsPath];
153 | NSEnumerator *e = [plugins objectEnumerator];
154 | NSString *s = nil;
155 | while (s = [e nextObject])
156 | {
157 | if ([[s pathExtension] isEqualToString:@"plugin"])
158 | {
159 | NSString *path = [pluginsPath stringByAppendingPathComponent:s];
160 | NSBundle *b = [NSBundle bundleWithPath:path];
161 | if (b)
162 | {
163 | [b load];
164 | Class c = [b principalClass];
165 | id obj = [c new];
166 | if (c && [c conformsToProtocol:@protocol(PluginManagerProtocol)])
167 | [self registerManager:obj];//[c new]];
168 | }
169 | else
170 | NSLog(@"Couldn't load plugin at path %@", _cmd, path);
171 | }
172 | }
173 | }
174 |
175 | +(NSString *)pathToPluginsFolder
176 | {
177 | return [[[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:[[NSProcessInfo processInfo] processName]] stringByAppendingPathComponent:@"Plugins"];
178 | }
179 |
180 | +(NSArray *)pluginFilesForSubmanager:(id)submanager {
181 | NSString *pluginPath = [self pathToPluginsFolder];
182 | NSArray *extensions = [submanager extensions];
183 | NSFileManager *fm = [NSFileManager defaultManager];
184 | NSMutableArray *pluginFiles = [NSMutableArray array];
185 |
186 | NSArray *files = [fm directoryContentsAtPath:pluginPath];
187 | for (NSString *file in files)
188 | if ([extensions containsObject:[file pathExtension]])
189 | [pluginFiles addObject:[pluginPath stringByAppendingPathComponent:file]];
190 |
191 | pluginPath = [[NSBundle mainBundle] builtInPlugInsPath];
192 | files = [fm directoryContentsAtPath:pluginPath];
193 | for (NSString *file in files)
194 | if ([extensions containsObject:[file pathExtension]])
195 | [pluginFiles addObject:[pluginPath stringByAppendingPathComponent:file]];
196 |
197 | return pluginFiles;
198 | }
199 |
200 | @end
201 |
--------------------------------------------------------------------------------
/src/PluginManagerApplescriptIncludes.h:
--------------------------------------------------------------------------------
1 | enum PluginAppleEventCodes {
2 | ASPluginForCode = 'foR_',
3 | ASPluginWithCode = 'wITh',
4 |
5 | // Event codes
6 | ASPluginPropertyEventCode = 'Xprp',
7 | ASPluginTitleEventCode = 'Xtit',
8 | ASPluginEnableEventCode = 'Xena',
9 | ASPluginPerformEventCode = 'Xprf',
10 | };
11 |
12 |
13 | #define ASCodify(x) [NSNumber numberWithUnsignedLong:x]
14 |
--------------------------------------------------------------------------------
/src/PluginManagerProtocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // PluginManagerProtocol.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | @protocol PluginManagerProtocol
10 |
11 | -(NSString *)name;
12 | -(NSArray *)extensions;
13 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue;
14 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
15 | -(id)runScriptAtPath:(NSString *)path;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/src/PythonPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #include
12 | #import "PluginManager.h"
13 |
14 | // Brought in from PyObjC
15 | typedef struct {
16 | PyObject_HEAD
17 | __strong id objc_object;
18 | int flags;
19 | } PyObjCObject;
20 |
21 | struct pyobjc_api {
22 | int api_version;
23 | size_t struct_len;
24 | PyTypeObject* class_type;
25 | PyTypeObject* object_type;
26 | PyTypeObject* select_type;
27 | void *register_method_mapping;
28 | int (*register_signature_mapping)(char*, PyObject *(*)(PyObject*, PyObject*, PyObject*), void (*)(void*, void*, void**, void*));
29 | id (*obj_get_object)(PyObject*);
30 | void (*obj_clear_object)(PyObject*);
31 | Class (*cls_get_class)(PyObject*);
32 | PyObject* (*cls_to_python)(Class cls);
33 | id (*python_to_id)(PyObject*);
34 | PyObject* (*id_to_python)(id);
35 | };
36 |
37 |
38 | typedef id(*PythonToId_t)(PyObject*);
39 | typedef PyObject*(*IdToPython_t)(id);
40 |
41 | PythonToId_t PythonToId;
42 | IdToPython_t IdToPython;
43 |
44 | @interface PythonPluginManager : NSObject {
45 | NSMutableDictionary *_plugins;
46 | }
47 |
48 | @property (retain) NSMutableDictionary *plugins;
49 |
50 | -(NSString *)name;
51 | -(NSArray *)extensions;
52 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)value;
53 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
54 | -(id)runScriptAtPath:(NSString *)path;
55 |
56 | @end
57 |
58 | id depythonify(PyObject *value);
59 | PyObject *pythonify(id value);
60 | PyObject *guaranteedTuple(PyObject *value);
61 |
62 | // A convenience method used internally by the PythonPluginManager that wraps some boilerplate code
63 | // around calling into a Python module.
64 | @interface PythonPluginManager (PrivateMethods)
65 | - (id)callFunction:(NSString *)functionName ofModule:(PyObject *)module arguments:(NSArray *)args;
66 | @end
67 |
--------------------------------------------------------------------------------
/src/PythonPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard.
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "PythonPluginManager.h"
10 |
11 | // depythonify attempts to turn a PyObject value into its id/Cocoa counterpart.
12 | id depythonify(PyObject *value) {
13 | return PythonToId(value);
14 |
15 | if (value == nil) return nil;
16 | if (PyInt_Check(value) || PyLong_Check(value) || PyBool_Check(value))
17 | return [NSNumber numberWithLong:PyInt_AsLong(value)];
18 | else if (PyFloat_Check(value)) return [NSNumber numberWithDouble:PyFloat_AsDouble(value)];
19 | else if (PyUnicode_Check(value)) return [NSString stringWithUTF8String:PyUnicode_AS_DATA(value)];
20 | else if (PyString_Check(value)) return [NSString stringWithUTF8String:PyString_AsString(value)];
21 | else if (PyTuple_Check(value)) {
22 | unsigned int size = PyTuple_Size(value);
23 | NSMutableArray *array = [NSMutableArray array];
24 | unsigned int idx = 0;
25 | for (idx = 0; idx < size; idx++) {
26 | id obj = depythonify(PyTuple_GetItem(value, idx));
27 | if (obj == nil) obj = [NSNull null];
28 | [array addObject:obj];
29 | }
30 | return [[array copy] autorelease]; // Convert to a standard array
31 | }
32 | else if (PyList_Check(value)) {
33 | unsigned int size = PyList_Size(value);
34 | NSMutableArray *array = [NSMutableArray array];
35 | unsigned int idx = 0;
36 | for (idx = 0; idx < size; idx++) {
37 | id obj = depythonify(PyList_GetItem(value, idx));
38 | if (obj == nil) obj = [NSNull null];
39 | [array addObject:obj];
40 | }
41 | return array;
42 | }
43 | else if (PyDict_Check(value)) {
44 | PyObject *keys = PyDict_Keys(value);
45 | unsigned int size = PyList_Size(keys);
46 | unsigned int idx = 0;
47 | NSMutableDictionary *dict = [NSMutableDictionary dictionary];
48 | for (idx = 0; idx < size; idx++) {
49 | PyObject *key = PyList_GetItem(keys, idx);
50 | PyObject *obj = PyDict_GetItem(value, key);
51 | id convertedObj = depythonify(obj);
52 | id convertedKey = depythonify(key);
53 | if (convertedKey && convertedObj) [dict setObject:convertedObj forKey:convertedKey];
54 | }
55 | return dict;
56 | }
57 | else if (value == Py_None) return [NSNull null];
58 | else {
59 | NSString *type = [NSString stringWithUTF8String:value->ob_type->tp_name];
60 | if ([type isEqualToString:@"True"]) return [NSNumber numberWithBool:YES];
61 | else if ([type isEqualToString:@"False"]) return [NSNumber numberWithBool:NO];
62 | Class c = NSClassFromString(type);
63 | if (c) {
64 | PyObjCObject *tmp = (PyObjCObject *)value;
65 | return tmp->objc_object;
66 | }
67 | }
68 |
69 | Class OC_PythonObj = NSClassFromString(@"OC_PythonObject");
70 | if (OC_PythonObj)
71 | return [[OC_PythonObj performSelector:@selector(newWithObject:) withObject:(id)value] autorelease];
72 | return nil;
73 | }
74 |
75 | // pythonify converts ids to their PyObject values.
76 | typedef PyObject *(*pyobjcobject_new_t)(id, int, int); // Function signature for PyObjCObject_New. Used in dynamic lookup.
77 | PyObject *pythonify(id value) {
78 | if (value == nil) return nil;
79 | if ([value isKindOfClass:[NSString class]]) return PyString_FromString([value UTF8String]);
80 | else if ([value isKindOfClass:[NSNumber class]]) return PyFloat_FromDouble([value doubleValue]);
81 | else if ([value isKindOfClass:[NSMutableArray class]]) {
82 | PyObject *list = PyList_New([value count]);
83 | NSEnumerator *valueEnumerator = [value objectEnumerator];
84 | id obj;
85 | unsigned int idx = 0;
86 | while (obj = [valueEnumerator nextObject]) PyList_SetItem(list, idx++, pythonify(obj));
87 | return list;
88 | }
89 | else if ([value isKindOfClass:[NSArray class]]) {
90 | PyObject *tuple = PyTuple_New([value count]);
91 | NSEnumerator *valueEnumerator = [value objectEnumerator];
92 | id obj;
93 | unsigned int idx = 0;
94 | while (obj = [valueEnumerator nextObject]) PyTuple_SetItem(tuple, idx++, pythonify(obj));
95 | return tuple;
96 | }
97 | else if ([value isKindOfClass:[NSDictionary class]]) {
98 | PyObject *dict = PyDict_New();
99 | NSArray *keys = [value allKeys];
100 | NSEnumerator *keyEnumerator = [keys objectEnumerator];
101 | id key;
102 | while (key = [keyEnumerator nextObject])
103 | {
104 | id obj = [value objectForKey:key];
105 | PyDict_SetItem(dict, pythonify(key), pythonify(obj));
106 | }
107 | return dict;
108 | }
109 | else if ([value isKindOfClass:[NSNull class]]) return Py_None;
110 |
111 | return IdToPython(value);
112 | }
113 |
114 | // I suspect that there's some strange interactions if multiple plugins are loaded.
115 | // NSArrays are comparably equivalent to NSMutableArrays by class but, of course, aren't mutable.
116 | // This generally isn't a problem (for those who know), but it means that this can't call Python methods
117 | // using the `pythonify` convenience function. I couldn't find an easy way to coerce python lists to tuples
118 | // so this was written to make sure that I get a tuple that can be used to call into Python methods
119 | PyObject *guaranteedTuple(PyObject *value) {
120 | if (value == nil) return nil;
121 | if (PyTuple_Check(value)) return value;
122 | NSArray *tmp = depythonify(value);
123 | NSEnumerator *tmpEnumerator = [tmp objectEnumerator];
124 | id obj;
125 | PyObject *tuple = PyTuple_New([tmp count]);
126 | unsigned int idx = 0;
127 | while (obj = [tmpEnumerator nextObject]) PyTuple_SetItem(tuple, idx++, pythonify(obj));
128 | return tuple;
129 | }
130 |
131 | @implementation PythonPluginManager
132 |
133 | @synthesize plugins = _plugins;
134 |
135 | +(void)load {
136 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
137 | [PluginManager registerManager:[[self new] autorelease]];
138 | [pool release];
139 | }
140 |
141 | -(NSString *)name { return @"Python"; }
142 | -(NSArray *)extensions { return [NSArray arrayWithObjects:@"py", @"python", nil]; }
143 |
144 | - (id)init
145 | {
146 | self = [super init];
147 | if (!self) return nil;
148 |
149 | Py_Initialize();
150 |
151 | return self;
152 | }
153 |
154 | - (void)dealloc
155 | {
156 | self.plugins = nil;
157 | Py_Finalize();
158 | [super dealloc];
159 | }
160 |
161 | - (void)build
162 | {
163 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
164 | self.plugins = plugins;
165 | for (NSString *path in [PluginManager pluginFilesForSubmanager:self]) {
166 | Py_SetProgramName("/usr/bin/python");
167 | FILE *pyFile = fopen([path fileSystemRepresentation], "r");
168 |
169 | // The main module (__main__ in Python) pretty much represents the Python script. When it is loaded,
170 | // the main module will contain references to the functions that will be called.
171 | PyObject *mainModule = PyImport_AddModule("__main__");
172 | PyObject *globals = PyModule_GetDict(mainModule);
173 |
174 | // Load the Python file using PyRun_File and then call the actionProperty() function
175 | PyRun_File(pyFile, [path UTF8String], Py_file_input, globals, globals);
176 |
177 | if (PythonToId == nil) {
178 | PyObject *objcModule = PyImport_Import(PyString_FromString("objc"));
179 | Py_DECREF(objcModule);
180 | PyObject *objcGlobals = PyModule_GetDict(objcModule);
181 | PyObject *apiObj = PyDict_GetItemString(objcGlobals, "__C_API__");
182 | struct pyobjc_api *pyobjc = PyCObject_AsVoidPtr(apiObj);
183 | PythonToId = pyobjc->python_to_id;
184 | IdToPython = pyobjc->id_to_python;
185 | }
186 |
187 | NSString *property = [self callFunction:@"actionProperty" ofModule:mainModule arguments:nil];
188 | if (!property) continue;
189 |
190 | NSMutableArray *arr = [plugins objectForKey:property];
191 | if (!arr) arr = [NSMutableArray array];
192 | [arr addObject:[NSValue valueWithPointer:mainModule]];
193 | [plugins setObject:arr forKey:property];
194 | }
195 | }
196 |
197 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
198 | {
199 | if (!self.plugins) [self build];
200 | NSArray *plugins = [self.plugins objectForKey:property];
201 | if (!plugins || ![plugins count]) return nil;
202 |
203 | NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
204 | NSValue *mainModuleValue;
205 | NSMutableArray *ret = [NSMutableArray array];
206 | // Python doesn't allow for functions with a dynamic number of arguments. Well, it does the *kwargs and **kwargs
207 | // stuff, but I'm not using it for this script. For this reason, the arguments must represent some object.
208 | // Since pythonify() converts NSNulls to Py_Nones, we're making sure that these values aren't just nil.
209 | forValue = forValue ? forValue : [NSNull null];
210 | withValue = withValue ? withValue : [NSNull null];
211 | NSArray *args = [NSArray arrayWithObjects:forValue, withValue, nil];
212 | while (mainModuleValue = [pluginEnumerator nextObject])
213 | {
214 | // Retrieve the main module and call its actionEnable() function with the forValue and the withValue
215 | // If the script decides that it should be enabled, get its title by calling actionTitle() and creating
216 | // the plugin dictionary.
217 | PyObject *mainModule = [mainModuleValue pointerValue];
218 | NSNumber *enabled = [self callFunction:@"actionEnable" ofModule:mainModule arguments:args];
219 | if ([enabled boolValue]) {
220 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
221 | [self callFunction:@"actionTitle" ofModule:mainModule arguments:args], @"title",
222 | mainModuleValue, @"module", nil]];
223 | }
224 | }
225 |
226 | return ret;
227 | }
228 |
229 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
230 | {
231 | // Like in pluginsForProperty:forValue:withValue:, the arguments should represent some real Python object.
232 | // We'll turn them into Py_Nones again if they are nil and then call actionPerform().
233 | PyObject *mainModule = [[plugin objectForKey:@"module"] pointerValue];
234 | NSArray *args = [NSArray arrayWithObjects:forValue ? forValue : [NSNull null], withValue ? withValue : [NSNull null], nil];
235 | [self callFunction:@"actionPerform" ofModule:mainModule arguments:args];
236 | }
237 |
238 | -(id)runScriptAtPath:(NSString *)path
239 | {
240 | // Can it get easier to call a Python script?
241 | // Note that this hasn't been tested. Due to the GIL state, it's possible that this could cause a crash.
242 | // More information on GIL states are documented in callFunction:ofModule:arguments:.
243 | FILE *pyFile = fopen([path UTF8String], "r");
244 | PyImport_ImportModule("objc");
245 | PyObject *mainModule = PyImport_AddModule("__main__");
246 | PyObject *globals = PyModule_GetDict(mainModule);
247 | return depythonify(PyRun_File(pyFile, [path UTF8String], Py_file_input, globals, globals));
248 | }
249 |
250 | // The PythonPluginManager calls into functions of a module fairly often and it tends to boilerplate code, so
251 | // this is a convenience method to make it easier.
252 | - (id)callFunction:(NSString *)functionName ofModule:(PyObject *)module arguments:(NSArray *)args {
253 | // In the PythonPluginManager, the module will usually be the main module. We get the function using
254 | // PyObject_GetAttrString from the module, check to see if it exists and is callable, and then call it with
255 | // PyObject_CallObject().
256 | PyObject *pFunc = PyObject_GetAttrString(module, [functionName UTF8String]);
257 | id ret = nil;
258 | if (pFunc && PyCallable_Check(pFunc)) {
259 | // The GIL state is a bit of a pain in the ass at first. If the user imports objc into Python, the app
260 | // will crash with some GIL state error. Simply using PyGILState_Ensure() and releasing the GIL state after
261 | // seems to resolve this issue.
262 | PyGILState_STATE state = PyGILState_Ensure();
263 | PyObject *pValue = PyObject_CallObject(pFunc, args ? guaranteedTuple(pythonify(args)) : nil);
264 | if (pValue == nil) PyErr_Print();
265 | else ret = depythonify(pValue);
266 | Py_XDECREF(pFunc);
267 | PyGILState_Release(state);
268 | }
269 | return ret;
270 | }
271 |
272 | @end
273 |
--------------------------------------------------------------------------------
/src/RubyPluginManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // RubyPluginManager.h
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "PluginManager.h"
12 | #import "PluginManagerProtocol.h"
13 |
14 | @interface RubyPluginManager : NSObject {
15 | NSMutableDictionary *_plugins;
16 | }
17 |
18 | @property (retain) NSMutableDictionary *plugins;
19 |
20 | -(NSString *)name;
21 | -(NSArray *)extensions;
22 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue;
23 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue;
24 | -(id)runScriptAtPath:(NSString *)path;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/src/RubyPluginManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // RubyPluginManager.m
3 | // PluginManager
4 | //
5 | // Created by Grayson Hansard
6 | // Copyright 2009 From Concentrate Software. All rights reserved.
7 | //
8 |
9 | #import "RubyPluginManager.h"
10 |
11 | @interface RubyPluginManager (PrivateMethods)
12 | -(void)build;
13 | - (id)callRubyMethod:(NSString *)method ofScript:(VALUE)script withArguments:(NSArray *)args;
14 | @end
15 |
16 | @implementation RubyPluginManager
17 |
18 | @synthesize plugins = _plugins;
19 |
20 | +(void)load {
21 | NSAutoreleasePool *pool = [NSAutoreleasePool new];
22 | if (NSClassFromString(@"MacRuby")) [PluginManager registerManager:[[self new] autorelease]];
23 | [pool release];
24 | }
25 |
26 | -(id)init
27 | {
28 | self = [super init];
29 | if (!self) return nil;
30 |
31 | return self;
32 | }
33 |
34 | -(void)build
35 | {
36 | NSMutableDictionary *plugins = [NSMutableDictionary dictionary];
37 | self.plugins = plugins;
38 |
39 | [MacRuby sharedRuntime];
40 | for (NSString *scriptPath in [PluginManager pluginFilesForSubmanager:self])
41 | {
42 | VALUE script = rb_eval_string([[NSString stringWithContentsOfFile:scriptPath] UTF8String]);
43 | NSString *property = [self callRubyMethod:@"actionProperty" ofScript:script withArguments:nil];
44 |
45 | NSMutableArray *arr = [plugins objectForKey:property];
46 | if (!arr) arr = [NSMutableArray array];
47 | [arr addObject:[NSValue valueWithPointer:(const void *)script]];
48 | [plugins setObject:arr forKey:property];
49 | }
50 | }
51 |
52 | -(NSString *)name { return @"Ruby"; }
53 | -(NSArray *)extensions { return [NSArray arrayWithObjects:@"rb", @"ruby", nil]; }
54 | -(NSArray *)pluginsForProperty:(NSString *)property forValue:(id)forValue withValue:(id)withValue
55 | {
56 | if (!self.plugins) [self build];
57 | NSArray *arr = [self.plugins objectForKey:property];
58 | if (!arr || ![arr count]) return nil;
59 |
60 | NSEnumerator *pluginEnumerator = [arr objectEnumerator];
61 | id rb;
62 | NSMutableArray *ret = [NSMutableArray array];
63 | NSArray *arguments = [NSArray arrayWithObjects:forValue ? forValue : [NSNull null], withValue ? withValue : [NSNull null], nil];
64 | while (rb = [pluginEnumerator nextObject])
65 | {
66 | VALUE script = (VALUE)[rb pointerValue];
67 | NSNumber *shouldEnable = [self callRubyMethod:@"actionEnable" ofScript:script withArguments:arguments];
68 | if ([shouldEnable boolValue])
69 | [ret addObject:[NSDictionary dictionaryWithObjectsAndKeys:
70 | [self callRubyMethod:@"actionTitle" ofScript:script withArguments:arguments], @"title",
71 | rb, @"plugin",
72 | forValue, @"forValue",
73 | withValue, @"value",
74 | nil]];
75 | }
76 |
77 | return ret;
78 | }
79 |
80 | -(void)runPlugin:(NSDictionary *)plugin forValue:(id)forValue withValue:(id)withValue
81 | {
82 | id rb = [plugin objectForKey:@"plugin"];
83 | NSArray *arguments = [NSArray arrayWithObjects:forValue ? forValue : [NSNull null], withValue ? withValue : [NSNull null], nil];
84 | [self callRubyMethod:@"actionPerform" ofScript:(VALUE)[rb pointerValue] withArguments:arguments];
85 | }
86 |
87 | -(id)runScriptAtPath:(NSString *)path
88 | {
89 | NSString *rubyCode = [NSString stringWithContentsOfFile:path];
90 | if (!rubyCode) return nil;
91 | VALUE ret = rb_eval_string([rubyCode UTF8String]);
92 | return RB2OC(ret);
93 | }
94 |
95 | - (id)callRubyMethod:(NSString *)method ofScript:(VALUE)script withArguments:(NSArray *)args {
96 | VALUE rubyArgs[ [args count] ];
97 | unsigned int idx = 0;
98 | for (id arg in args) rubyArgs[idx++] = OC2RB(arg);
99 | VALUE ret = rb_funcall2(script, rb_intern([method UTF8String]), [args count], rubyArgs);
100 | if (ret) return RB2OC(ret);
101 | return nil;
102 | }
103 |
104 | @end
105 |
--------------------------------------------------------------------------------