Package net.sourceforge.marathon.ruby

Source Code of net.sourceforge.marathon.ruby.ModuleList

/*******************************************************************************
*  Copyright (C) 2010 Jalian Systems Private Ltd.
*  Copyright (C) 2010 Contributors to Marathon OSS Project
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Library General Public
*  License as published by the Free Software Foundation; either
*  version 2 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Library General Public License for more details.
*
*  You should have received a copy of the GNU Library General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*  Project website: http://www.marathontesting.com
*  Help: Marathon help forum @ http://groups.google.com/group/marathon-testing
*
*******************************************************************************/
package net.sourceforge.marathon.ruby;

import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import net.sourceforge.marathon.api.module.Argument;
import net.sourceforge.marathon.api.module.Argument.Type;
import net.sourceforge.marathon.api.module.Function;
import net.sourceforge.marathon.api.module.Module;

import org.jruby.Ruby;
import org.jrubyparser.Parser;
import org.jrubyparser.ast.ArgsNode;
import org.jrubyparser.ast.ArrayNode;
import org.jrubyparser.ast.BignumNode;
import org.jrubyparser.ast.DefnNode;
import org.jrubyparser.ast.FCallNode;
import org.jrubyparser.ast.FalseNode;
import org.jrubyparser.ast.FixnumNode;
import org.jrubyparser.ast.FloatNode;
import org.jrubyparser.ast.INameNode;
import org.jrubyparser.ast.ListNode;
import org.jrubyparser.ast.LocalAsgnNode;
import org.jrubyparser.ast.Node;
import org.jrubyparser.ast.RegexpNode;
import org.jrubyparser.ast.StrNode;
import org.jrubyparser.ast.TrueNode;
import org.jrubyparser.lexer.Lexer;
import org.jrubyparser.lexer.LexerSource;
import org.jrubyparser.parser.ParserConfiguration;
import org.jrubyparser.parser.Tokens;

public class ModuleList {
    private Module topModule;
    private final String[] moduleDirs;
    private final Ruby interpreter;

    public ModuleList(Ruby interpreter, String[] moduleDirs) {
        this.interpreter = interpreter;
        this.moduleDirs = moduleDirs;
        topModule = importModules();
    }

    public ModuleList(Ruby newInstance, String moduleDir) {
        this(newInstance, new String[] { moduleDir });
    }

    private Module importModules() {
        Module top = loadModulesFromFSMulti();
        top.setName("Functions");
        return top;
    }

    private Module loadModulesFromFSMulti() {
        Module module = new Module("Functions", null);
        for (int i = 0; i < moduleDirs.length; i++) {
            File file = new File(moduleDirs[i]);
            File[] files = file.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    if (pathname.getName().startsWith("."))
                        return false;
                    return pathname.isDirectory() || pathname.getName().endsWith(".rb");
                }
            });
            for (File child : files) {
                Module m = loadModulesFromFS(child, module);
                if (m != null)
                    module.addChild(m);
            }
        }
        return module;
    }

    private Module loadModulesFromFS(File file, Module parent) {
        if (file.isDirectory()) {
            Module module = new Module(getModuleName(file), parent);
            File[] files = file.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    if (pathname.getName().startsWith("."))
                        return false;
                    return pathname.isDirectory() || pathname.getName().endsWith(".rb");
                }
            });
            for (File child : files) {
                Module m = loadModulesFromFS(child, module);
                if (m != null)
                    module.addChild(m);
            }
            if (module.getChildren().size() > 0)
                return module;
            return null;
        }
        return loadFunctionsFromFile(file, parent);
    }

    private Module loadFunctionsFromFile(File file, Module parent) {
        try {
            Properties docNodes = collectDocNodes(file);
            Module module = new Module(getModuleName(file), true, parent);
            Parser parser = new Parser();
            Node node = parser.parse(file.getName(), new FileReader(file), new ParserConfiguration());
            List<Node> defnNodes = findNodes(node, new INodeFilter() {

                public void visitStart(Node node) {
                }

                public void visitEnd(Node node) {
                }

                public boolean accept(Node node) {
                    return node instanceof DefnNode;
                }
            });
            for (Node defn : defnNodes) {
                addNodeToModule((DefnNode) defn, module, docNodes);
            }
            return module;
        } catch (Throwable t) {
            new Exception("Error processing: " + file, t).printStackTrace();
        }
        return null;
    }

    private Properties collectDocNodes(File file) throws IOException {
        Lexer lexer = new Lexer();
        lexer.setSource(LexerSource.getSource(file.getName(), new FileReader(file), new ParserConfiguration()));
        lexer.setPreserveSpaces(true);
        lexer.setWarnings(new Parser.NullWarnings());
        String doc;
        int token = -1;
        Properties props = new Properties();
        while (lexer.advance()) {
            if (token == -1)
                token = lexer.token();
            if (token == Tokens.tDOCUMENTATION) {
                doc = "=" + lexer.getTokenBuffer().toString();
                while (lexer.advance() && (token = lexer.token()) == Tokens.tWHITESPACE) {
                }
                if (token != Tokens.kDEF)
                    continue;
                while (lexer.advance() && (token = lexer.token()) == Tokens.tWHITESPACE) {
                }
                if (token != Tokens.tIDENTIFIER)
                    continue;
                props.setProperty(lexer.getTokenBuffer().toString(), doc);
            }
            token = -1;
        }
        return props;
    }

    private void addNodeToModule(DefnNode defn, Module module, Properties docNodes) {
        List<Argument> args = new ArrayList<Argument>();
        ArgsNode argsNode = defn.getArgsNode();
        if (argsNode.getBlock() != null)
            return;
        ListNode pre = argsNode.getPre();
        if (pre != null) {
            for (int i = 0; i < pre.size(); i++) {
                Node node = pre.get(i);
                if (node instanceof INameNode)
                    args.add(new Argument(((INameNode) node).getName()));
                else
                    return;
            }
        }
        ListNode optional = argsNode.getOptional();
        if (optional != null) {
            for (int i = 0; i < optional.size(); i++) {
                Node node = optional.get(i);
                if (!(node instanceof LocalAsgnNode))
                    return;
                LocalAsgnNode lan = (LocalAsgnNode) node;
                Node valueNode = lan.getValueNode();
                if ((valueNode instanceof StrNode))
                    args.add(new Argument(lan.getName(), argEncode(((StrNode) valueNode).getValue().toString()), Type.STRING));
                else if (valueNode instanceof RegexpNode)
                    args.add(new Argument(lan.getName(), ((RegexpNode) valueNode).getValue().toString(), Type.REGEX));
                else if (valueNode instanceof BignumNode)
                    args.add(new Argument(lan.getName(), "" + ((BignumNode) valueNode).getValue().toString(), Type.NUMBER));
                else if (valueNode instanceof FixnumNode)
                    args.add(new Argument(lan.getName(), ((FixnumNode) valueNode).getValue() + "", Type.NUMBER));
                else if (valueNode instanceof FloatNode)
                    args.add(new Argument(lan.getName(), ((FloatNode) valueNode).getValue() + "", Type.NUMBER));
                else if (valueNode instanceof TrueNode)
                    args.add(new Argument(lan.getName(), ((TrueNode) valueNode).getName(), Type.BOOLEAN));
                else if (valueNode instanceof FalseNode)
                    args.add(new Argument(lan.getName(), ((FalseNode) valueNode).getName(), Type.BOOLEAN));
                else if (valueNode instanceof ArrayNode && ((ArrayNode) valueNode).size() > 0) {
                    ArrayNode arrayNode = (ArrayNode) valueNode;
                    List<String> argValue = getListValue(arrayNode);
                    if (argValue != null) {
                        Node node2 = arrayNode.get(0);
                        Type type = Type.NONE;
                        if (node2 instanceof StrNode)
                            type = Type.STRING;
                        else if (node2 instanceof RegexpNode)
                            type = Type.REGEX;
                        else if (node instanceof BignumNode || node instanceof FixnumNode || node instanceof FloatNode)
                            type = Type.NUMBER;
                        args.add(new Argument(lan.getName(), argValue, type));
                    } else
                        return;
                } else {
                    return;
                }
            }
        }
        String name = defn.getName();
        Function f = module.addFunction(name, args, docNodes.getProperty(name));
        f.setWindow(getWindowName(defn));
        return;
    }

    private List<String> getListValue(ArrayNode arrayNode) {
        boolean isString = false;
        boolean isRegex = false;
        boolean isNumber = false;
        Node node = arrayNode.get(0);
        if (node instanceof StrNode)
            isString = true;
        else if (node instanceof RegexpNode)
            isRegex = true;
        else if (node instanceof BignumNode || node instanceof FixnumNode || node instanceof FloatNode)
            isNumber = true;
        else
            return null;

        List<String> l = new ArrayList<String>();
        for (int i = 0; i < arrayNode.size(); i++) {
            Node anode = arrayNode.get(i);
            if (isString && anode instanceof StrNode) {
                l.add(argEncode(((StrNode) anode).getValue().toString()));
            } else if (isRegex && anode instanceof RegexpNode) {
                l.add("/" + ((RegexpNode) anode).getValue().toString() + "/");
            } else if (isNumber && anode instanceof BignumNode) {
                l.add("" + ((BignumNode) anode).getValue().toString());
            } else if (isNumber && anode instanceof FixnumNode) {
                l.add("" + ((FixnumNode) anode).getValue());
            } else if (isNumber && anode instanceof FloatNode) {
                l.add("" + ((FloatNode) anode).getValue());
            } else
                return null;
        }
        return l;
    }

    private String getWindowName(DefnNode defn) {
        final FCallNode[] callNodes = { null };

        findNodes(defn, new INodeFilter() {

            public void visitStart(Node node) {
            }

            public void visitEnd(Node node) {
            }

            public boolean accept(Node node) {
                if (node instanceof FCallNode && ((FCallNode) node).getName().equals("with_window") && callNodes[0] == null) {
                    callNodes[0] = (FCallNode) node;
                }
                return false;
            }
        });
        if (callNodes[0] == null)
            return null;
        return validWithCallNode(callNodes[0]);
    }

    private String validWithCallNode(FCallNode node) {
        Node argsNode = node.getArgsNode();
        if (!(argsNode instanceof ArrayNode))
            return null;
        ArrayNode aNode = (ArrayNode) argsNode;
        if (aNode.size() != 1)
            return null;
        Node node2 = aNode.get(0);
        if (!(node2 instanceof StrNode))
            return null;
        return ((StrNode) node2).getValue();
    }

    private String argEncode(String string) {
        String s = interpreter.newString(string).inspect().toString();
        if (s.length() >= 2 && s.startsWith("\"") && s.endsWith("\""))
            return s.substring(1, s.length() - 1);
        return s;
    }

    private String getModuleName(File file) {
        String name = file.getName();
        if (file.isDirectory())
            return name;
        return name.substring(0, name.length() - 3);
    }

    public Module getTop() {
        return topModule;
    }

    public interface INodeFilter {

        public boolean accept(Node node);

        public void visitStart(Node node);

        public void visitEnd(Node node);
    }

    public static List<Node> findNodes(Node root, INodeFilter filter) {
        ArrayList<Node> nodes = new ArrayList<Node>();
        return findNodes(root, nodes, filter);
    }

    private static List<Node> findNodes(Node root, ArrayList<Node> nodes, INodeFilter filter) {
        filter.visitStart(root);
        if (filter.accept(root))
            nodes.add(root);
        List<Node> childNodes = root.childNodes();
        for (Node child : childNodes) {
            findNodes(child, nodes, filter);
        }
        filter.visitEnd(root);
        return nodes;
    }

}
TOP

Related Classes of net.sourceforge.marathon.ruby.ModuleList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.