PageRenderTime 67ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/IronPython_Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs

#
C# | 1089 lines | 781 code | 197 blank | 111 comment | 123 complexity | 35edf797b45daf08b57568aa6bb37ed9 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Runtime.CompilerServices;
  18. using System.Runtime.InteropServices;
  19. using IronRuby.Compiler;
  20. using IronRuby.Runtime;
  21. using IronRuby.Runtime.Calls;
  22. using Microsoft.Scripting.Actions;
  23. using Microsoft.Scripting.Runtime;
  24. using Microsoft.Scripting.Utils;
  25. using Microsoft.Scripting.Generation;
  26. using Microsoft.Scripting;
  27. using System.Diagnostics;
  28. namespace IronRuby.Builtins {
  29. [RubyClass("Module", Extends = typeof(RubyModule), Inherits = typeof(Object), Restrictions = ModuleRestrictions.Builtin | ModuleRestrictions.NoUnderlyingType)]
  30. public static class ModuleOps {
  31. #region initialize, initialize_copy
  32. [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)]
  33. public static object Reinitialize(BlockParam block, RubyModule/*!*/ self) {
  34. // no class can be reinitialized:
  35. if (self.IsClass) {
  36. throw RubyExceptions.CreateTypeError("already initialized class");
  37. }
  38. return (block != null) ? RubyUtils.EvaluateInModule(self, block, null) : null;
  39. }
  40. [RubyMethod("initialize_copy", RubyMethodAttributes.PrivateInstance)]
  41. public static RubyModule/*!*/ InitializeCopy(RubyModule/*!*/ self, object other) {
  42. // no class can be reinitialized:
  43. if (self.IsClass) {
  44. throw RubyExceptions.CreateTypeError("already initialized class");
  45. }
  46. // self could be a meta-module:
  47. RubyClass selfClass = self.Context.GetClassOf(self);
  48. RubyClass otherClass = self.Context.GetClassOf(other);
  49. if (otherClass != selfClass) {
  50. throw RubyExceptions.CreateTypeError("initialize_copy should take same class object");
  51. }
  52. self.InitializeModuleCopy((RubyModule)other);
  53. return self;
  54. }
  55. #endregion
  56. #region extend_object, extended, include, included
  57. // thread-safe:
  58. [RubyMethod("extend_object", RubyMethodAttributes.PrivateInstance)]
  59. public static object ExtendObject(RubyModule/*!*/ self, object extendedObject) {
  60. // include self into extendedObject's singleton
  61. self.Context.GetOrCreateSingletonClass(extendedObject).IncludeModules(self);
  62. return extendedObject;
  63. }
  64. [RubyMethod("extended", RubyMethodAttributes.PrivateInstance)]
  65. public static void ObjectExtended(RubyModule/*!*/ self, object extendedObject) {
  66. // extendedObject has been extended by self, i.e. self has been included into extendedObject's singleton class
  67. }
  68. [RubyMethod("include", RubyMethodAttributes.PrivateInstance)]
  69. public static RubyModule/*!*/ Include(
  70. CallSiteStorage<Func<CallSite, RubyModule, RubyModule, object>>/*!*/ appendFeaturesStorage,
  71. CallSiteStorage<Func<CallSite, RubyModule, RubyModule, object>>/*!*/ includedStorage,
  72. RubyModule/*!*/ self, [NotNullItems]params RubyModule/*!*/[]/*!*/ modules) {
  73. RubyUtils.RequireMixins(self, modules);
  74. var appendFeatures = appendFeaturesStorage.GetCallSite("append_features", 1);
  75. var included = includedStorage.GetCallSite("included", 1);
  76. // Kernel#append_features inserts the module at the beginning of ancestors list;
  77. // ancestors after include: [modules[0], modules[1], ..., modules[N-1], self, ...]
  78. for (int i = modules.Length - 1; i >= 0; i--) {
  79. appendFeatures.Target(appendFeatures, modules[i], self);
  80. included.Target(included, modules[i], self);
  81. }
  82. return self;
  83. }
  84. [RubyMethod("included", RubyMethodAttributes.PrivateInstance)]
  85. public static void Included(RubyModule/*!*/ self, RubyModule/*!*/ owner) {
  86. // self has been included into owner
  87. }
  88. // thread-safe:
  89. [RubyMethod("append_features", RubyMethodAttributes.PrivateInstance)]
  90. public static RubyModule/*!*/ AppendFeatures(RubyModule/*!*/ self, [NotNull]RubyModule/*!*/ owner) {
  91. owner.IncludeModules(self);
  92. return self;
  93. }
  94. #endregion
  95. #region private, protected, public, private_class_method, public_class_method, module_function
  96. // thread-safe:
  97. [RubyMethod("private", RubyMethodAttributes.PrivateInstance)]
  98. public static RubyModule/*!*/ SetPrivateVisibility(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  99. [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ methodNames) {
  100. // overwrites methods to instance:
  101. SetMethodAttributes(scope, self, methodNames, RubyMethodAttributes.PrivateInstance);
  102. return self;
  103. }
  104. // thread-safe:
  105. [RubyMethod("protected", RubyMethodAttributes.PrivateInstance)]
  106. public static RubyModule/*!*/ SetProtectedVisibility(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  107. [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ methodNames) {
  108. // overwrites methods to instance:
  109. SetMethodAttributes(scope, self, methodNames, RubyMethodAttributes.ProtectedInstance);
  110. return self;
  111. }
  112. // thread-safe:
  113. [RubyMethod("public", RubyMethodAttributes.PrivateInstance)]
  114. public static RubyModule/*!*/ SetPublicVisibility(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  115. [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ methodNames) {
  116. // overwrites methods to instance:
  117. SetMethodAttributes(scope, self, methodNames, RubyMethodAttributes.PublicInstance);
  118. return self;
  119. }
  120. // thread-safe:
  121. [RubyMethodAttribute("private_class_method")]
  122. public static RubyModule/*!*/ MakeClassMethodsPrivate(RubyModule/*!*/ self,
  123. [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ methodNames) {
  124. SetMethodAttributes(self.GetOrCreateSingletonClass(), methodNames, RubyMethodAttributes.Private);
  125. return self;
  126. }
  127. // thread-safe:
  128. [RubyMethodAttribute("public_class_method")]
  129. public static RubyModule/*!*/ MakeClassMethodsPublic(RubyModule/*!*/ self,
  130. [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ methodNames) {
  131. SetMethodAttributes(self.GetOrCreateSingletonClass(), methodNames, RubyMethodAttributes.Public);
  132. return self;
  133. }
  134. // thread-safe:
  135. [RubyMethod("module_function", RubyMethodAttributes.PrivateInstance)]
  136. public static RubyModule/*!*/ CopyMethodsToModuleSingleton(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  137. [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ methodNames) {
  138. // This is an important restriction for correct super calls in module functions (see RubyOps.DefineMethod).
  139. // MRI has it wrong. It checks just here and not in method definition.
  140. if (self.IsClass) {
  141. throw RubyExceptions.CreateTypeError("module_function must be called for modules");
  142. }
  143. // overwrites visibility to public:
  144. SetMethodAttributes(scope, self, methodNames, RubyMethodAttributes.ModuleFunction);
  145. return self;
  146. }
  147. internal static void SetMethodAttributes(RubyScope/*!*/ scope, RubyModule/*!*/ module, string/*!*/[]/*!*/ methodNames, RubyMethodAttributes attributes) {
  148. if (methodNames.Length == 0) {
  149. scope.GetMethodAttributesDefinitionScope().MethodAttributes = attributes;
  150. } else {
  151. SetMethodAttributes(module, methodNames, attributes);
  152. }
  153. }
  154. internal static void SetMethodAttributes(RubyModule/*!*/ module, string/*!*/[]/*!*/ methodNames, RubyMethodAttributes attributes) {
  155. var context = module.Context;
  156. bool isModuleFunction = (attributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction;
  157. var instanceVisibility = isModuleFunction ? RubyMethodVisibility.Private :
  158. (RubyMethodVisibility)(attributes & RubyMethodAttributes.VisibilityMask);
  159. foreach (string methodName in methodNames) {
  160. RubyMemberInfo method;
  161. // we need to define new methods one by one since the method_added events can define a new method that might be used here:
  162. using (context.ClassHierarchyLocker()) {
  163. MethodLookup options = MethodLookup.FallbackToObject;
  164. if (!isModuleFunction) {
  165. options |= MethodLookup.ReturnForwarder;
  166. }
  167. method = module.ResolveMethodNoLock(methodName, VisibilityContext.AllVisible, options).Info;
  168. if (method == null) {
  169. throw RubyExceptions.CreateUndefinedMethodError(module, methodName);
  170. }
  171. // MRI only adds method to the target module if visibility differs:
  172. if (method.Visibility != instanceVisibility) {
  173. module.SetVisibilityNoEventNoLock(context, methodName, method, instanceVisibility);
  174. }
  175. if (isModuleFunction) {
  176. module.SetModuleFunctionNoEventNoLock(context, methodName, method);
  177. }
  178. }
  179. if (method.Visibility != instanceVisibility) {
  180. module.MethodAdded(methodName);
  181. }
  182. if (isModuleFunction) {
  183. module.GetOrCreateSingletonClass().MethodAdded(methodName);
  184. }
  185. }
  186. }
  187. #endregion
  188. #region define_method (thread-safe)
  189. // thread-safe:
  190. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  191. public static RubyMethod/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  192. [DefaultProtocol, NotNull]string/*!*/ methodName, [NotNull]RubyMethod/*!*/ method) {
  193. DefineMethod(scope, self, methodName, method.Info, method.GetTargetClass());
  194. return method;
  195. }
  196. // thread-safe:
  197. // Defines method using mangled CLR name and aliases that method with the actual CLR name.
  198. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  199. public static RubyMethod/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  200. [NotNull]ClrName/*!*/ methodName, [NotNull]RubyMethod/*!*/ method) {
  201. var result = DefineMethod(scope, self, methodName.MangledName, method);
  202. if (methodName.HasMangledName) {
  203. self.AddMethodAlias(methodName.ActualName, methodName.MangledName);
  204. }
  205. return result;
  206. }
  207. // thread-safe:
  208. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  209. public static UnboundMethod/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  210. [DefaultProtocol, NotNull]string/*!*/ methodName, [NotNull]UnboundMethod/*!*/ method) {
  211. DefineMethod(scope, self, methodName, method.Info, method.TargetConstraint);
  212. return method;
  213. }
  214. // thread-safe:
  215. // Defines method using mangled CLR name and aliases that method with the actual CLR name.
  216. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  217. public static UnboundMethod/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  218. [NotNull]ClrName/*!*/ methodName, [NotNull]UnboundMethod/*!*/ method) {
  219. var result = DefineMethod(scope, self, methodName.MangledName, method);
  220. if (methodName.HasMangledName) {
  221. self.AddMethodAlias(methodName.ActualName, methodName.MangledName);
  222. }
  223. return result;
  224. }
  225. private static void DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self, string/*!*/ methodName, RubyMemberInfo/*!*/ info,
  226. RubyModule/*!*/ targetConstraint) {
  227. var visibility = GetDefinedMethodVisibility(scope, self, methodName);
  228. using (self.Context.ClassHierarchyLocker()) {
  229. // MRI 1.8 does the check when the method is called, 1.9 checks it upfront as we do:
  230. if (!self.HasAncestorNoLock(targetConstraint)) {
  231. throw RubyExceptions.CreateTypeError(
  232. "bind argument must be a subclass of {0}", targetConstraint.GetName(scope.RubyContext)
  233. );
  234. }
  235. self.SetDefinedMethodNoEventNoLock(self.Context, methodName, info, visibility);
  236. }
  237. self.MethodAdded(methodName);
  238. }
  239. // thread-safe:
  240. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  241. public static Proc/*!*/ DefineMethod(RubyScope/*!*/ scope, [NotNull]BlockParam/*!*/ block,
  242. RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ methodName) {
  243. return DefineMethod(scope, self, methodName, block.Proc);
  244. }
  245. // thread-safe:
  246. // Defines method using mangled CLR name and aliases that method with the actual CLR name.
  247. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  248. public static Proc/*!*/ DefineMethod(RubyScope/*!*/ scope, [NotNull]BlockParam/*!*/ block,
  249. RubyModule/*!*/ self, [NotNull]ClrName/*!*/ methodName) {
  250. var result = DefineMethod(scope, block, self, methodName.MangledName);
  251. if (methodName.HasMangledName) {
  252. self.AddMethodAlias(methodName.ActualName, methodName.MangledName);
  253. }
  254. return result;
  255. }
  256. // thread-safe:
  257. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  258. public static Proc/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  259. [DefaultProtocol, NotNull]string/*!*/ methodName, [NotNull]Proc/*!*/ block) {
  260. var visibility = GetDefinedMethodVisibility(scope, self, methodName);
  261. var info = Proc.ToLambdaMethodInfo(block, methodName, visibility, self);
  262. self.AddMethod(scope.RubyContext, methodName, info);
  263. return info.Lambda;
  264. }
  265. // thread-safe:
  266. [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)]
  267. public static Proc/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self,
  268. [NotNull]ClrName/*!*/ methodName, [NotNull]Proc/*!*/ block) {
  269. var result = DefineMethod(scope, self, methodName.MangledName, block);
  270. if (methodName.HasMangledName) {
  271. self.AddMethodAlias(methodName.ActualName, methodName.MangledName);
  272. }
  273. return result;
  274. }
  275. private static RubyMethodVisibility GetDefinedMethodVisibility(RubyScope/*!*/ scope, RubyModule/*!*/ module, string/*!*/ methodName) {
  276. // MRI: Special names are private.
  277. // MRI: Doesn't create a singleton method if module_function is used in the scope, however the private visibility is applied (bug?)
  278. // MRI 1.8: uses the current scope's visibility only if the target module is the same as the scope's module (bug?)
  279. // MFI 1.9: always uses public visibility (bug?)
  280. RubyMethodVisibility visibility;
  281. if (scope.RubyContext.RubyOptions.Compatibility < RubyCompatibility.Ruby19) {
  282. var attributesScope = scope.GetMethodAttributesDefinitionScope();
  283. if (attributesScope.GetInnerMostModuleForMethodLookup() == module) {
  284. bool isModuleFunction = (attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction;
  285. visibility = (isModuleFunction) ? RubyMethodVisibility.Private : attributesScope.Visibility;
  286. } else {
  287. visibility = RubyMethodVisibility.Public;
  288. }
  289. } else {
  290. visibility = RubyMethodVisibility.Public;
  291. }
  292. return RubyUtils.GetSpecialMethodVisibility(visibility, methodName);
  293. }
  294. #endregion
  295. #region method_(added|removed|undefined)
  296. [RubyMethod("method_added", RubyMethodAttributes.PrivateInstance | RubyMethodAttributes.Empty)]
  297. public static void MethodAdded(object/*!*/ self, object methodName) {
  298. // nop
  299. }
  300. [RubyMethod("method_removed", RubyMethodAttributes.PrivateInstance | RubyMethodAttributes.Empty)]
  301. public static void MethodRemoved(object/*!*/ self, object methodName) {
  302. // nop
  303. }
  304. [RubyMethod("method_undefined", RubyMethodAttributes.PrivateInstance | RubyMethodAttributes.Empty)]
  305. public static void MethodUndefined(object/*!*/ self, object methodName) {
  306. // nop
  307. }
  308. #endregion
  309. #region attr, attr_{reader|writer|accessor} (thread-safe)
  310. private static void DefineAccessor(RubyScope/*!*/ scope, RubyModule/*!*/ self, string/*!*/ name, bool readable, bool writable) {
  311. // MRI: ignores ModuleFunction scope flag (doesn't create singleton methods):
  312. if (!Tokenizer.IsVariableName(name)) {
  313. throw RubyExceptions.CreateNameError("invalid attribute name `{0}'", name);
  314. }
  315. var varName = "@" + name;
  316. var attributesScope = scope.GetMethodAttributesDefinitionScope();
  317. if (readable) {
  318. var flags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, name);
  319. self.AddMethod(scope.RubyContext, name, new RubyAttributeReaderInfo(flags, self, varName));
  320. }
  321. if (writable) {
  322. self.AddMethod(scope.RubyContext, name + "=", new RubyAttributeWriterInfo((RubyMemberFlags)attributesScope.Visibility, self, varName));
  323. }
  324. }
  325. // thread-safe:
  326. [RubyMethod("attr", RubyMethodAttributes.PrivateInstance)]
  327. public static void Attr(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ name, [Optional]bool writable) {
  328. DefineAccessor(scope, self, name, true, writable);
  329. }
  330. // thread-safe:
  331. [RubyMethod("attr", RubyMethodAttributes.PrivateInstance)]
  332. public static void Attr(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ names) {
  333. foreach (string name in names) {
  334. DefineAccessor(scope, self, name, true, false);
  335. }
  336. }
  337. // thread-safe:
  338. [RubyMethod("attr_accessor", RubyMethodAttributes.PrivateInstance)]
  339. public static void AttrAccessor(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ name) {
  340. DefineAccessor(scope, self, name, true, true);
  341. }
  342. // thread-safe:
  343. [RubyMethod("attr_accessor", RubyMethodAttributes.PrivateInstance)]
  344. public static void AttrAccessor(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ names) {
  345. foreach (string name in names) {
  346. DefineAccessor(scope, self, name, true, true);
  347. }
  348. }
  349. // thread-safe:
  350. [RubyMethod("attr_reader", RubyMethodAttributes.PrivateInstance)]
  351. public static void AttrReader(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ name) {
  352. DefineAccessor(scope, self, name, true, false);
  353. }
  354. // thread-safe:
  355. [RubyMethod("attr_reader", RubyMethodAttributes.PrivateInstance)]
  356. public static void AttrReader(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ names) {
  357. foreach (string name in names) {
  358. DefineAccessor(scope, self, name, true, false);
  359. }
  360. }
  361. // thread-safe:
  362. [RubyMethod("attr_writer", RubyMethodAttributes.PrivateInstance)]
  363. public static void AttrWriter(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ name) {
  364. DefineAccessor(scope, self, name, false, true);
  365. }
  366. // thread-safe:
  367. [RubyMethod("attr_writer", RubyMethodAttributes.PrivateInstance)]
  368. public static void AttrWriter(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNullItems]params string/*!*/[]/*!*/ names) {
  369. foreach (string name in names) {
  370. DefineAccessor(scope, self, name, false, true);
  371. }
  372. }
  373. #endregion
  374. #region alias_method, remove_method, undef_method
  375. // thread-safe:
  376. [RubyMethod("alias_method", RubyMethodAttributes.PrivateInstance)]
  377. public static RubyModule/*!*/ AliasMethod(RubyContext/*!*/ context, RubyModule/*!*/ self,
  378. [DefaultProtocol, NotNull]string/*!*/ newName, [DefaultProtocol, NotNull]string/*!*/ oldName) {
  379. self.AddMethodAlias(newName, oldName);
  380. return self;
  381. }
  382. // thread-safe:
  383. [RubyMethod("remove_method", RubyMethodAttributes.PrivateInstance)]
  384. public static RubyModule/*!*/ RemoveMethod(RubyModule/*!*/ self, [DefaultProtocol, NotNullItems]params string[]/*!*/ methodNames) {
  385. foreach (var methodName in methodNames) {
  386. // MRI: reports a warning and allows removal
  387. if (self.IsBasicObjectClass && methodName == Symbols.Initialize) {
  388. throw RubyExceptions.CreateNameError("Cannot remove BasicObject#initialize");
  389. }
  390. if (!self.RemoveMethod(methodName)) {
  391. throw RubyExceptions.CreateUndefinedMethodError(self, methodName);
  392. }
  393. }
  394. return self;
  395. }
  396. // thread-safe:
  397. [RubyMethod("undef_method", RubyMethodAttributes.PrivateInstance)]
  398. public static RubyModule/*!*/ UndefineMethod(RubyModule/*!*/ self, [DefaultProtocol, NotNullItems]params string[]/*!*/ methodNames) {
  399. foreach (var methodName in methodNames) {
  400. if (!self.ResolveMethod(methodName, VisibilityContext.AllVisible).Found) {
  401. throw RubyExceptions.CreateUndefinedMethodError(self, methodName);
  402. }
  403. self.UndefineMethod(methodName);
  404. }
  405. return self;
  406. }
  407. #endregion
  408. #region <, >, <=, >=, <=>, ==, ===, ancestors, included_modules, include? (thread-safe)
  409. // thread-safe:
  410. [RubyMethod("==")]
  411. public static bool Equals(RubyModule/*!*/ self, object other) {
  412. return ReferenceEquals(self, other);
  413. }
  414. // thread-safe:
  415. [RubyMethod("===")]
  416. public static bool CaseEquals(RubyModule/*!*/ self, object other) {
  417. return self.Context.IsKindOf(other, self);
  418. }
  419. // thread-safe:
  420. [RubyMethod("<")]
  421. public static object IsSubclassOrIncluded(RubyModule/*!*/ self, [NotNull]RubyModule/*!*/ module) {
  422. if (ReferenceEquals(self, module)) {
  423. return ScriptingRuntimeHelpers.False;
  424. }
  425. return self.HasAncestor(module) ? ScriptingRuntimeHelpers.True : null;
  426. }
  427. // thread-safe:
  428. [RubyMethod("<=")]
  429. public static object IsSubclassSameOrIncluded(RubyModule/*!*/ self, [NotNull]RubyModule/*!*/ module) {
  430. if (self.Context != module.Context) {
  431. return null;
  432. }
  433. using (self.Context.ClassHierarchyLocker()) {
  434. if (self.HasAncestorNoLock(module)) {
  435. return ScriptingRuntimeHelpers.True;
  436. }
  437. return module.HasAncestorNoLock(self) ? ScriptingRuntimeHelpers.False : null;
  438. }
  439. }
  440. // thread-safe:
  441. [RubyMethod(">")]
  442. public static object IsNotSubclassOrIncluded(RubyModule/*!*/ self, [NotNull]RubyModule/*!*/ module) {
  443. if (ReferenceEquals(self, module)) {
  444. return false;
  445. }
  446. return module.HasAncestor(self) ? ScriptingRuntimeHelpers.True : null;
  447. }
  448. // thread-safe:
  449. [RubyMethod(">=")]
  450. public static object IsNotSubclassSameOrIncluded(RubyModule/*!*/ self, [NotNull]RubyModule/*!*/ module) {
  451. if (self.Context != module.Context) {
  452. return null;
  453. }
  454. using (self.Context.ClassHierarchyLocker()) {
  455. if (module.HasAncestorNoLock(self)) {
  456. return ScriptingRuntimeHelpers.True;
  457. }
  458. return self.HasAncestorNoLock(module) ? ScriptingRuntimeHelpers.False : null;
  459. }
  460. }
  461. // thread-safe:
  462. [RubyMethod("<=>")]
  463. public static object Comparison(RubyModule/*!*/ self, [NotNull]RubyModule/*!*/ module) {
  464. if (ReferenceEquals(self, module)) {
  465. return ClrInteger.Zero;
  466. }
  467. if (self.Context != module.Context) {
  468. return null;
  469. }
  470. using (self.Context.ClassHierarchyLocker()) {
  471. if (self.HasAncestorNoLock(module)) {
  472. return ClrInteger.MinusOne;
  473. }
  474. if (module.HasAncestorNoLock(self)) {
  475. return ClrInteger.One;
  476. }
  477. }
  478. return null;
  479. }
  480. [RubyMethod("<=>")]
  481. public static object Comparison(RubyModule/*!*/ self, object module) {
  482. return null;
  483. }
  484. [RubyMethod("<")]
  485. [RubyMethod(">")]
  486. [RubyMethod("<=")]
  487. [RubyMethod(">=")]
  488. public static object InvalidComparison(RubyModule/*!*/ self, object module) {
  489. throw RubyExceptions.CreateTypeError("compared with non class/module");
  490. }
  491. // thread-safe:
  492. [RubyMethod("ancestors")]
  493. public static RubyArray/*!*/ Ancestors(RubyModule/*!*/ self) {
  494. RubyArray ancestors = new RubyArray();
  495. using (self.Context.ClassHierarchyLocker()) {
  496. self.ForEachAncestor(true, delegate(RubyModule/*!*/ module) {
  497. if (!module.IsSingletonClass) {
  498. ancestors.Add(module);
  499. }
  500. return false;
  501. });
  502. }
  503. return ancestors;
  504. }
  505. // thread-safe:
  506. [RubyMethod("included_modules")]
  507. public static RubyArray/*!*/ GetIncludedModules(RubyModule/*!*/ self) {
  508. RubyArray ancestorModules = new RubyArray();
  509. using (self.Context.ClassHierarchyLocker()) {
  510. self.ForEachAncestor(true, delegate(RubyModule/*!*/ module) {
  511. if (module != self && !module.IsClass && !ancestorModules.Contains(module)) {
  512. ancestorModules.Add(module);
  513. }
  514. return false;
  515. });
  516. }
  517. return ancestorModules;
  518. }
  519. // thread-safe:
  520. [RubyMethod("include?")]
  521. public static bool IncludesModule(RubyModule/*!*/ self, [NotNull]RubyModule/*!*/ other) {
  522. if (other.IsClass) {
  523. throw RubyExceptions.CreateTypeError("wrong argument type Class (expected Module)");
  524. }
  525. return other != self && self.HasAncestor(other);
  526. }
  527. #endregion
  528. #region (module|class)_(eval|exec)
  529. [RubyMethod("module_eval")]
  530. [RubyMethod("class_eval")]
  531. public static object Evaluate(RubyScope/*!*/ scope, BlockParam block, RubyModule/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ code,
  532. [Optional, NotNull]MutableString file, [DefaultParameterValue(1)]int line) {
  533. if (block != null) {
  534. throw RubyExceptions.CreateArgumentError("wrong number of arguments");
  535. }
  536. return RubyUtils.Evaluate(code, scope, self, self, file, line);
  537. }
  538. [RubyMethod("module_eval")]
  539. [RubyMethod("class_eval")]
  540. public static object Evaluate([NotNull]BlockParam/*!*/ block, RubyModule/*!*/ self) {
  541. return RubyUtils.EvaluateInModule(self, block, null);
  542. }
  543. // This method is not available in 1.8 so far, but since the usual workaround is very inefficient it is useful to have it in 1.8 as well.
  544. [RubyMethod("module_exec")]
  545. [RubyMethod("class_exec")]
  546. public static object Execute([NotNull]BlockParam/*!*/ block, RubyModule/*!*/ self, params object[]/*!*/ args) {
  547. return RubyUtils.EvaluateInModule(self, block, args);
  548. }
  549. #endregion
  550. #region class_variables, class_variable_defined?, class_variable_get, class_variable_set, remove_class_variable
  551. // not thread-safe
  552. [RubyMethod("class_variables")]
  553. public static RubyArray/*!*/ ClassVariables(RubyModule/*!*/ self) {
  554. var result = new RubyArray();
  555. self.EnumerateClassVariables((module, name, value) => {
  556. result.Add(self.Context.StringifyIdentifier(name));
  557. return false;
  558. });
  559. return result;
  560. }
  561. // not thread-safe:
  562. [RubyMethod("class_variable_defined?")]
  563. public static bool IsClassVariableDefined(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ variableName) {
  564. object value;
  565. if (self.TryResolveClassVariable(variableName, out value) == null) {
  566. RubyUtils.CheckClassVariableName(variableName);
  567. return false;
  568. }
  569. return true;
  570. }
  571. // not thread-safe:
  572. [RubyMethod("class_variable_get", RubyMethodAttributes.PrivateInstance)]
  573. public static object GetClassVariable(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ variableName) {
  574. object value;
  575. if (self.TryResolveClassVariable(variableName, out value) == null) {
  576. RubyUtils.CheckClassVariableName(variableName);
  577. throw RubyExceptions.CreateNameError("uninitialized class variable {0} in {1}", variableName, self.Name);
  578. }
  579. return value;
  580. }
  581. // not thread-safe:
  582. [RubyMethod("class_variable_set", RubyMethodAttributes.PrivateInstance)]
  583. public static object ClassVariableSet(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ variableName, object value) {
  584. RubyUtils.CheckClassVariableName(variableName);
  585. self.SetClassVariable(variableName, value);
  586. return value;
  587. }
  588. // not thread-safe:
  589. [RubyMethod("remove_class_variable", RubyMethodAttributes.PrivateInstance)]
  590. public static object RemoveClassVariable(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ variableName) {
  591. object value;
  592. if (!self.TryGetClassVariable(variableName, out value)) {
  593. RubyUtils.CheckClassVariableName(variableName);
  594. throw RubyExceptions.CreateNameError("class variable {0} not defined for {1}", variableName, self.Name);
  595. }
  596. self.RemoveClassVariable(variableName);
  597. return value;
  598. }
  599. #endregion
  600. #region constants, const_defined?, const_set, const_get, remove_const, const_missing
  601. // thread-safe:
  602. [RubyMethod("constants", RubyMethodAttributes.PublicSingleton)]
  603. public static RubyArray/*!*/ GetGlobalConstants(RubyModule/*!*/ self, [DefaultParameterValue(true)]bool inherited) {
  604. return GetDefinedConstants(self.Context.ObjectClass, inherited);
  605. }
  606. // thread-safe:
  607. [RubyMethod("constants")]
  608. public static RubyArray/*!*/ GetDefinedConstants(RubyModule/*!*/ self, [DefaultParameterValue(true)]bool inherited) {
  609. var result = new RubyArray();
  610. if (inherited) {
  611. var visited = new Dictionary<string, bool>();
  612. bool hideGlobalConstants = !self.IsObjectClass;
  613. using (self.Context.ClassHierarchyLocker()) {
  614. self.ForEachConstant(true, delegate(RubyModule/*!*/ module, string name, object value) {
  615. if (name == null) {
  616. // terminate enumeration when Object is reached
  617. return hideGlobalConstants && module.IsObjectClass;
  618. }
  619. if (!visited.ContainsKey(name)) {
  620. if (Tokenizer.IsConstantName(name)) {
  621. result.Add(self.Context.StringifyIdentifier(name));
  622. }
  623. visited.Add(name, true);
  624. }
  625. return false;
  626. });
  627. }
  628. } else {
  629. using (self.Context.ClassHierarchyLocker()) {
  630. self.EnumerateConstants((module, name, value) => {
  631. if (Tokenizer.IsConstantName(name)) {
  632. result.Add(self.Context.StringifyIdentifier(name));
  633. }
  634. return false;
  635. });
  636. }
  637. }
  638. return result;
  639. }
  640. // thread-safe:
  641. [RubyMethod("const_defined?")]
  642. public static bool IsConstantDefined(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ constantName) {
  643. RubyUtils.CheckConstantName(constantName);
  644. object constant;
  645. // MRI checks declared constans only and don't trigger autoload:
  646. return self.TryGetConstant(null, constantName, out constant);
  647. }
  648. // thread-safe:
  649. [RubyMethod("const_get")]
  650. public static object GetConstantValue(RubyScope/*!*/ scope, RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ constantName) {
  651. return RubyUtils.GetConstant(scope.GlobalScope, self, constantName, true);
  652. }
  653. // thread-safe:
  654. [RubyMethod("const_set")]
  655. public static object SetConstantValue(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ constantName, object value) {
  656. RubyUtils.CheckConstantName(constantName);
  657. RubyUtils.SetConstant(self, constantName, value);
  658. return value;
  659. }
  660. // thread-safe:
  661. [RubyMethod("remove_const", RubyMethodAttributes.PrivateInstance)]
  662. public static object RemoveConstant(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ constantName) {
  663. object value;
  664. if (!self.TryRemoveConstant(constantName, out value)) {
  665. RubyUtils.CheckConstantName(constantName);
  666. throw RubyExceptions.CreateNameError("constant {0}::{1} not defined", self.Name, constantName);
  667. }
  668. return value;
  669. }
  670. [RubyMethod("const_missing")]
  671. public static object ConstantMissing(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ name) {
  672. return self.Context.ResolveMissingConstant(self, name);
  673. }
  674. #endregion
  675. #region autoload, autoload?
  676. // thread-safe:
  677. [RubyMethod("autoload")]
  678. public static void SetAutoloadedConstant(RubyModule/*!*/ self,
  679. [DefaultProtocol, NotNull]string/*!*/ constantName, [DefaultProtocol, NotNull]MutableString/*!*/ path) {
  680. RubyUtils.CheckConstantName(constantName);
  681. if (path.IsEmpty) {
  682. throw RubyExceptions.CreateArgumentError("empty file name");
  683. }
  684. self.SetAutoloadedConstant(constantName, path);
  685. }
  686. // thread-safe:
  687. [RubyMethod("autoload?")]
  688. public static MutableString GetAutoloadedConstantPath(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ constantName) {
  689. return self.GetAutoloadedConstantPath(constantName);
  690. }
  691. #endregion
  692. #region {private_|protected_|public_|}instance_methods (thread-safe)
  693. // thread-safe:
  694. [RubyMethod("instance_methods")]
  695. public static RubyArray/*!*/ GetInstanceMethods(RubyModule/*!*/ self) {
  696. return GetInstanceMethods(self, true);
  697. }
  698. // thread-safe:
  699. [RubyMethod("instance_methods")]
  700. public static RubyArray/*!*/ GetInstanceMethods(RubyModule/*!*/ self, bool inherited) {
  701. return GetMethods(self, inherited, RubyMethodAttributes.PublicInstance | RubyMethodAttributes.ProtectedInstance);
  702. }
  703. // thread-safe:
  704. [RubyMethod("private_instance_methods")]
  705. public static RubyArray/*!*/ GetPrivateInstanceMethods(RubyModule/*!*/ self) {
  706. return GetPrivateInstanceMethods(self, true);
  707. }
  708. // thread-safe:
  709. [RubyMethod("private_instance_methods")]
  710. public static RubyArray/*!*/ GetPrivateInstanceMethods(RubyModule/*!*/ self, bool inherited) {
  711. return GetMethods(self, inherited, RubyMethodAttributes.PrivateInstance);
  712. }
  713. // thread-safe:
  714. [RubyMethod("protected_instance_methods")]
  715. public static RubyArray/*!*/ GetProtectedInstanceMethods(RubyModule/*!*/ self) {
  716. return GetProtectedInstanceMethods(self, true);
  717. }
  718. // thread-safe:
  719. [RubyMethod("protected_instance_methods")]
  720. public static RubyArray/*!*/ GetProtectedInstanceMethods(RubyModule/*!*/ self, bool inherited) {
  721. return GetMethods(self, inherited, RubyMethodAttributes.ProtectedInstance);
  722. }
  723. // thread-safe:
  724. [RubyMethod("public_instance_methods")]
  725. public static RubyArray/*!*/ GetPublicInstanceMethods(RubyModule/*!*/ self) {
  726. return GetPublicInstanceMethods(self, true);
  727. }
  728. // thread-safe:
  729. [RubyMethod("public_instance_methods")]
  730. public static RubyArray/*!*/ GetPublicInstanceMethods(RubyModule/*!*/ self, bool inherited) {
  731. return GetMethods(self, inherited, RubyMethodAttributes.PublicInstance);
  732. }
  733. internal static RubyArray/*!*/ GetMethods(RubyModule/*!*/ self, bool inherited, RubyMethodAttributes attributes) {
  734. return GetMethods(self, inherited, attributes, null);
  735. }
  736. internal static RubyArray/*!*/ GetMethods(RubyModule/*!*/ self, bool inherited, RubyMethodAttributes attributes,
  737. IEnumerable<string> foreignMembers) {
  738. var result = new RubyArray();
  739. using (self.Context.ClassHierarchyLocker()) {
  740. self.ForEachMember(inherited, attributes, foreignMembers, (name, module, member) => {
  741. if (member.IsInteropMember && (module.Restrictions & ModuleRestrictions.NoNameMapping) == 0 && RubyUtils.HasMangledName(name)) {
  742. if (Tokenizer.IsMethodName(name) || Tokenizer.IsOperatorName(name)) {
  743. result.Add(new ClrName(name));
  744. }
  745. } else {
  746. result.Add(self.Context.StringifyIdentifier(name));
  747. }
  748. });
  749. }
  750. return result;
  751. }
  752. #endregion
  753. #region {private_|protected_|public_|}method_defined? (thread-safe)
  754. // thread-safe:
  755. [RubyMethod("method_defined?")]
  756. public static bool MethodDefined(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ methodName) {
  757. RubyMemberInfo method = self.ResolveMethod(methodName, VisibilityContext.AllVisible).Info;
  758. return method != null && method.Visibility != RubyMethodVisibility.Private;
  759. }
  760. // thread-safe:
  761. [RubyMethod("private_method_defined?")]
  762. public static bool PrivateMethodDefined(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ methodName) {
  763. RubyMemberInfo method = self.ResolveMethod(methodName, VisibilityContext.AllVisible).Info;
  764. return method != null && method.Visibility == RubyMethodVisibility.Private;
  765. }
  766. // thread-safe:
  767. [RubyMethod("protected_method_defined?")]
  768. public static bool ProtectedMethodDefined(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ methodName) {
  769. RubyMemberInfo method = self.ResolveMethod(methodName, VisibilityContext.AllVisible).Info;
  770. return method != null && method.Visibility == RubyMethodVisibility.Protected;
  771. }
  772. // thread-safe:
  773. [RubyMethod("public_method_defined?")]
  774. public static bool PublicMethodDefined(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ methodName) {
  775. RubyMemberInfo method = self.ResolveMethod(methodName, VisibilityContext.AllVisible).Info;
  776. return method != null && method.Visibility == RubyMethodVisibility.Public;
  777. }
  778. #endregion
  779. #region instance_method, 1.9: public_instance_method
  780. // thread-safe:
  781. [RubyMethod("instance_method")]
  782. public static UnboundMethod/*!*/ GetInstanceMethod(RubyModule/*!*/ self, [DefaultProtocol, NotNull]string/*!*/ methodName) {
  783. RubyMemberInfo method = self.ResolveMethod(methodName, VisibilityContext.AllVisible).Info;
  784. if (method == null) {
  785. throw RubyExceptions.CreateUndefinedMethodError(self, methodName);
  786. }
  787. RubyModule constraint = self;
  788. if (self.IsSingletonClass && method.DeclaringModule != self) {
  789. constraint = ((RubyClass)self).SuperClass;
  790. }
  791. // unbound method binable to any class with "constraint" mixin:
  792. return new UnboundMethod(constraint, methodName, method);
  793. }
  794. #endregion
  795. #region to_s, name, freeze
  796. [RubyMethod("to_s")]
  797. public static MutableString/*!*/ ToS(RubyContext/*!*/ context, RubyModule/*!*/ self) {
  798. return self.GetDisplayName(context, false);
  799. }
  800. [RubyMethod("name")]
  801. public static MutableString/*!*/ GetName(RubyContext/*!*/ context, RubyModule/*!*/ self) {
  802. return self.GetDisplayName(context, true);
  803. }
  804. [RubyMethod("freeze")]
  805. public static RubyModule/*!*/ Freeze(RubyContext/*!*/ context, RubyModule/*!*/ self) {
  806. self.Freeze();
  807. return self;
  808. }
  809. #endregion
  810. #region IronRuby: to_clr_type, of, []
  811. [RubyMethod("to_clr_type")]
  812. public static Type ToClrType(RubyModule/*!*/ self) {
  813. return self.TypeTracker != null ? self.TypeTracker.Type : null;
  814. }
  815. [RubyMethod("to_clr_ref")]
  816. public static RubyModule ToClrRef(RubyModule/*!*/ self) {
  817. try {
  818. return self.TypeTracker != null ? self.Context.GetClass(self.TypeTracker.Type.MakeByRefType()) : null;
  819. } catch (Exception) {
  820. throw RubyExceptions.CreateTypeError(
  821. "Cannot create by-ref type for `{0}'", self.Context.GetTypeName(self.TypeTracker.Type, true)
  822. );
  823. }
  824. }
  825. [RubyMethod("of")]
  826. [RubyMethod("[]")]
  827. public static RubyModule/*!*/ Of(RubyModule/*!*/ self, [NotNullItems]params object/*!*/[]/*!*/ typeArgs) {
  828. if (self.TypeTracker == null) {
  829. throw RubyExceptions.CreateArgumentError("'{0}' is not a type", self.Name);
  830. }
  831. Type type = self.TypeTracker.Type;
  832. int provided = typeArgs.Length;
  833. if (provided == 1 && type == typeof(Array)) {
  834. Type elementType = Protocols.ToType(self.Context, typeArgs[0]);
  835. Type arrayType;
  836. try {
  837. arrayType = elementType.MakeArrayType();
  838. } catch (Exception) {
  839. throw RubyExceptions.CreateTypeError(
  840. "Cannot create array type for `{0}'", self.Context.GetTypeName(elementType, true)
  841. );
  842. }
  843. return self.Context.GetModule(arrayType);
  844. }
  845. if (!type.IsGenericTypeDefinition) {
  846. if (provided > 0) {
  847. throw RubyExceptions.CreateArgumentError("`{0}' is not a generic type definition", self.Name);
  848. }
  849. return self;
  850. }
  851. int required = type.GetGenericArguments().Length;
  852. if (required != provided) {
  853. throw RubyExceptions.CreateArgumentError("Type `{0}' requires {1} generic type arguments, {2} provided", self.Name, required, provided);
  854. }
  855. Type concreteType = type.MakeGenericType(Protocols.ToTypes(self.Context, typeArgs));
  856. return self.Context.GetModule(concreteType);
  857. }
  858. [RubyMethod("of")]
  859. [RubyMethod("[]")]
  860. public static RubyModule/*!*/ Of(RubyModule/*!*/ self, int genericArity) {
  861. if (self.TypeTracker == null) {
  862. throw RubyExceptions.CreateArgumentError("`{0}' is not a type", self.Name);
  863. }
  864. Type type = self.TypeTracker.Type;
  865. if (!type.IsGenericTypeDefinition) {
  866. if (genericArity > 0) {
  867. throw RubyExceptions.CreateArgumentError("`{0}' is not a generic type definition", self.Name);
  868. }
  869. return self;
  870. }
  871. if (type.GetGenericArguments().Length != genericArity) {
  872. throw RubyExceptions.CreateArgumentError("`{0}' does not have generic arity {1}", self.Name, genericArity);
  873. }
  874. return self;
  875. }
  876. #endregion
  877. #region nesting
  878. [RubyMethod("nesting", RubyMethodAttributes.PublicSingleton)]
  879. public static RubyArray/*!*/ GetLexicalModuleNesting(RubyScope/*!*/ scope, RubyModule/*!*/ self) {
  880. RubyArray result = new RubyArray();
  881. do {
  882. // Ruby 1.9: the anonymous module doesn't show up
  883. if (scope.Module != null) {
  884. result.Add(scope.Module);
  885. }
  886. scope = (RubyScope)scope.Parent;
  887. } while (scope != null);
  888. return result;
  889. }
  890. #endregion
  891. }
  892. }