PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/RubyPlugin/src/org/jedit/ruby/cache/RubyCache.java

#
Java | 301 lines | 235 code | 44 blank | 22 comment | 31 complexity | ac9b32ae107eff3b0901831bb21ec2cd MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * RubyCache.java - Cache of Ruby methods, classes, modules
  3. *
  4. * Copyright 2005 Robert McKinnon
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. package org.jedit.ruby.cache;
  21. import org.jedit.ruby.ast.*;
  22. import org.jedit.ruby.parser.RubyParser;
  23. import org.jedit.ruby.RubyPlugin;
  24. import java.util.*;
  25. /**
  26. * @author robmckinnon at users.sourceforge.net
  27. */
  28. public final class RubyCache {
  29. private static RubyCache instance;
  30. private final NameToMethods nameToMethods;
  31. private final NameToParents nameToParents;
  32. private final MethodToParents methodToParents;
  33. private final ParentToMethods parentToMethods;
  34. private final ParentToImmediateMethods parentToImmediateMethods;
  35. private final Map<String, RubyMembers> pathToMembers;
  36. public static synchronized void resetCache() {
  37. instance = new RubyCache();
  38. }
  39. public static synchronized RubyCache instance() {
  40. return instance;
  41. }
  42. private RubyCache() {
  43. nameToMethods = new NameToMethods();
  44. nameToParents = new NameToParents();
  45. methodToParents = new MethodToParents();
  46. parentToMethods = new ParentToMethods();
  47. parentToImmediateMethods = new ParentToImmediateMethods();
  48. pathToMembers = new HashMap<String, RubyMembers>();
  49. nameToParents.setParentToImmediateMethods(parentToImmediateMethods);
  50. parentToMethods.setNameToParents(nameToParents);
  51. }
  52. public final synchronized void addMembers(String text, String path) {
  53. RubyMembers members = RubyParser.getMembers(text, path, null, true);
  54. addMembers(members, path);
  55. }
  56. public final synchronized void addMembers(RubyMembers members, String path) {
  57. if (!members.containsErrors()) {
  58. add(members, path);
  59. }
  60. }
  61. public final synchronized void addClass(ClassMember parent, String path) {
  62. Member[] members = new Member[1];
  63. members[0] = parent;
  64. RubyMembers rubyMembers = new RubyMembers(members, new ArrayList<Problem>(), 0);
  65. RubyCache.instance().addMembers(rubyMembers, path);
  66. }
  67. public final synchronized ClassMember getClass(String className) {
  68. return nameToParents.getClass(className);
  69. }
  70. public final synchronized ParentMember getParentMember(String parentMemberName) {
  71. return nameToParents.getMember(parentMemberName);
  72. }
  73. public final synchronized List<Method> getMethods(String method) {
  74. return new ArrayList<Method>(nameToMethods.getMethods(method));
  75. }
  76. public final synchronized Set<Member> getMembersWithMethod(String method) {
  77. return new HashSet<Member>(methodToParents.getParentSet(method));
  78. }
  79. public final synchronized Set<Method> getMethodsOfMember(String memberName) {
  80. return new HashSet<Method>(parentToMethods.getMethodSet(memberName));
  81. }
  82. public final synchronized Set<Method> getAllMethods() {
  83. return parentToMethods.getAllMethods();
  84. }
  85. public final synchronized List<Member> getAllImmediateMembers() {
  86. return new ArrayList<Member>(nameToParents.getAllMembers());
  87. }
  88. public final synchronized List<Member> getMembersWithMethodAsList(String method) {
  89. return new ArrayList<Member>(methodToParents.getParentList(method));
  90. }
  91. public final synchronized List<Method> getMethodsOfMemberAsList(String memberName) {
  92. return new ArrayList<Method>(parentToMethods.getMethodList(memberName));
  93. }
  94. public final synchronized void populateSuperClassMethods() {
  95. Collection<ParentMember> allParents = nameToParents.getAllParents();
  96. for (ParentMember member : allParents) {
  97. member.accept(new MemberVisitorAdapter() {
  98. public void handleClass(ClassMember classMember) {
  99. populateSuperClassMethods(classMember, classMember);
  100. }
  101. });
  102. }
  103. if (nameToParents.getMember("ActionController::Base") != null) {
  104. ClassMember appController = new ClassMember("ApplicationController");
  105. appController.setSuperClassName("ActionController::Base");
  106. appController.setEndOffset(0);
  107. appController.setDocumentationComment(
  108. "<p>ApplicationController is the parent of all the controller classes in a Rails application." +
  109. " By default in app/controllers there is a file called application.rb that contains an empty" +
  110. " definition of class ApplicationController.</p>" +
  111. "<p>This class is used to establish a context for the entire application." +
  112. " Filters added to this controller will be run for all controllers in the application." +
  113. " Likewise, all the methods added will be available for all controllers.</p>");
  114. addClass(appController, "ApplicationController");
  115. populateSuperClassMethods(appController, appController);
  116. }
  117. Set<Method> methods = getAllMethods();
  118. for (Method method : methods) {
  119. method.populateReturnTypes();
  120. }
  121. }
  122. private void add(RubyMembers members, String path) {
  123. parentToMethods.resetAllMethodsList();
  124. pathToMembers.put(path, members);
  125. members.visitMembers(new MemberVisitorAdapter() {
  126. public void handleModule(Module module) {
  127. parentToImmediateMethods.add(module);
  128. parentToMethods.add(module);
  129. nameToParents.add(module);
  130. }
  131. public void handleClass(ClassMember classMember) {
  132. parentToImmediateMethods.add(classMember);
  133. parentToMethods.add(classMember);
  134. nameToParents.add(classMember);
  135. }
  136. public void handleMethod(Method method) {
  137. methodToParents.add(method);
  138. nameToMethods.add(method);
  139. }
  140. });
  141. }
  142. private final static String[] ACTION_CONTROLLER_BASE_INCLUDES = new String[]{
  143. "ActionController::Filters",
  144. "ActionController::Layout",
  145. "ActionController::Flash",
  146. "ActionController::Benchmarking",
  147. "ActionController::Rescue",
  148. "ActionController::Dependencies",
  149. "ActionController::Pagination",
  150. "ActionController::Scaffolding",
  151. "ActionController::Helpers",
  152. "ActionController::Cookies",
  153. "ActionController::Caching",
  154. "ActionController::Components",
  155. "ActionController::Verification",
  156. "ActionController::Streaming",
  157. "ActionController::SessionManagement",
  158. "ActionController::Macros::AutoComplete",
  159. "ActionController::Macros::InPlaceEditing"
  160. };
  161. private final static String[] ACTIVE_RECORD_BASE_INCLUDES = new String[]{
  162. "ActiveRecord::Validations",
  163. "ActiveRecord::Locking",
  164. "ActiveRecord::Callbacks",
  165. "ActiveRecord::Observing",
  166. "ActiveRecord::Timestamp",
  167. "ActiveRecord::Associations",
  168. "ActiveRecord::Aggregations",
  169. "ActiveRecord::Transactions",
  170. "ActiveRecord::Reflection",
  171. "ActiveRecord::Acts::Tree",
  172. "ActiveRecord::Acts::List",
  173. "ActiveRecord::Acts::NestedSet"
  174. };
  175. private void populateSuperClassMethods(ClassMember member, ClassMember memberOrSuperclass) {
  176. if (memberOrSuperclass.hasSuperClassName()) {
  177. String superClassName = memberOrSuperclass.getSuperClassName();
  178. ClassMember superClass = nameToParents.getClass(superClassName);
  179. if (superClass != null) {
  180. addSuperClassMethods(member, superClass.getMethods());
  181. populateSuperClassMethods(member, superClass);
  182. }
  183. addIncludes(member, "ActiveRecord::Base", ACTIVE_RECORD_BASE_INCLUDES);
  184. addIncludes(member, "ActionController::Base", ACTION_CONTROLLER_BASE_INCLUDES);
  185. }
  186. }
  187. private void addIncludes(ClassMember member, String fullName, String[] includeModules) {
  188. if (member.getFullName().equals(fullName)) {
  189. for (String include : includeModules) {
  190. ClassMember classMethodClass = nameToParents.getClass(include + "::ClassMethods");
  191. if (classMethodClass != null && classMethodClass.getMethods().size() > 0) {
  192. includeClassMethods(member, classMethodClass);
  193. } else {
  194. classMethodClass = nameToParents.getClass(include);
  195. if (classMethodClass != null) {
  196. includeClassMethods(member, classMethodClass);
  197. }
  198. }
  199. }
  200. }
  201. }
  202. private void includeClassMethods(ClassMember member, ClassMember classMethodClass) {
  203. Set<Method> methods = classMethodClass.getMethods();
  204. Set<Method> classMethods = new HashSet<Method>();
  205. for (Method classMethod : methods) {
  206. classMethod.setClassMethod(true);
  207. classMethods.add(classMethod);
  208. }
  209. addSuperClassMethods(member, classMethods);
  210. }
  211. private void addSuperClassMethods(ClassMember member, Set<Method> superClassMethods) {
  212. for (Method method : superClassMethods) {
  213. methodToParents.add(method, member);
  214. }
  215. superClassMethods = filterOutDuplicates(member, superClassMethods);
  216. parentToMethods.add(member, superClassMethods);
  217. }
  218. private Set<Method> filterOutDuplicates(ParentMember member, Set<Method> parentMethods) {
  219. Set<String> methodNames = getMethodNames(member);
  220. Iterator<Method> parentMethodIterator = parentMethods.iterator();
  221. while (parentMethodIterator.hasNext()) {
  222. Method parentMethod = parentMethodIterator.next();
  223. if (methodNames.contains(parentMethod.getName())) {
  224. parentMethodIterator.remove();
  225. }
  226. }
  227. return parentMethods;
  228. }
  229. private Set<String> getMethodNames(ParentMember member) {
  230. Set<Method> methods = parentToMethods.getMethodSet(member.getName());
  231. Set<String> methodNames = new HashSet<String>();
  232. for (Method method : methods) {
  233. methodNames.add(method.getName());
  234. }
  235. return methodNames;
  236. }
  237. public List<ParentMember> getParentsStartingWith(String partialClass, boolean ignoreCase) {
  238. List<ParentMember> members = new ArrayList<ParentMember>();
  239. List<String> names = nameToParents.getAllParentNames();
  240. String lowerCasePartial = null;
  241. if (ignoreCase && partialClass != null) {
  242. lowerCasePartial = partialClass.toLowerCase();
  243. }
  244. for (String name : names) {
  245. if (name.startsWith(partialClass)) {
  246. ParentMember member = nameToParents.getMember(name);
  247. members.add(member);
  248. } else if (ignoreCase && lowerCasePartial != null) {
  249. if (name.toLowerCase().startsWith(lowerCasePartial)) {
  250. ParentMember member = nameToParents.getMember(name);
  251. members.add(member);
  252. }
  253. }
  254. }
  255. return members;
  256. }
  257. }