diff --git a/README b/README index 2a3bb94..7ea0bef 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ To build & use Harmonious Code on Unix-like operating systems: * Make sure you're running haXe 2. * Download the PHP documentation from CVS. * Copy/symlink the phpdoc/phpbook/phpbook-xsl/version.xml file from the - PHP documentationinto the data directory as version.xml. + PHP documentation into the data directory as version.xml. * Run build/test.sh. This will take a while as functions_tokens_cache.hxd is built in the data directory. It will also ensure everything's working correctly. @@ -15,6 +15,26 @@ To build & use Harmonious Code on Unix-like operating systems: * Run build/command_line.sh and pass the path to a PHP file as the first parameter. A basic analysis should appear. +To automatically ignore certain tokens and modules, place lines like +the following in your code: + +* To globally ignore a token (ex: json_decode()), place at the top of + the file the following: + + //harmonious json_decode + +* To ignore a token within a block of code, surround the code in the + following: + + //harmonious json_decode + ...your code... + //harmonious_end + +* To ignore a particular module throughout the code (ex: maxdb), place + at the top of the file the following: + + //harmonious @maxdb + No build instructions for Windows yet, but Cygwin + haXe for Windows should be able to perform the build. diff --git a/src/CodeParser.hx b/src/CodeParser.hx index 43a7f0a..53d1ca7 100644 --- a/src/CodeParser.hx +++ b/src/CodeParser.hx @@ -1,8 +1,10 @@ class CodeParser { - public var tokenProcessors(getTokenProcessors, null) : Hash; + public var token_processors(get_token_processors, null) : Hash; + public var ignored_modules(get_ignored_modules, null) : Hash; public function new() { - this.tokenProcessors = new Hash(); + this.token_processors = new Hash(); + this.ignored_modules = new Hash(); } #if neko @@ -13,7 +15,7 @@ class CodeParser { functionProcessor.save_to_cache(); } - this.tokenProcessors.set(Type.getClassName(Type.getClass(functionProcessor)), functionProcessor); + this.token_processors.set(Type.getClassName(Type.getClass(functionProcessor)), functionProcessor); } #end @@ -21,10 +23,11 @@ class CodeParser { var functionProcessor = new FunctionTokenProcessor(); functionProcessor.load_from_resource(); - this.tokenProcessors.set(Type.getClassName(Type.getClass(functionProcessor)), functionProcessor); + this.token_processors.set(Type.getClassName(Type.getClass(functionProcessor)), functionProcessor); } - public function getTokenProcessors() { return this.tokenProcessors; } + public function get_token_processors() { return this.token_processors; } + public function get_ignored_modules() { return this.ignored_modules; } private function flatten_tokens_to_ignore(tokens_to_ignore : Array>) : Hash { var flattened_tokens = new Hash(); @@ -38,8 +41,9 @@ class CodeParser { public function parse(s : String) : Array { var results = new Array(); + this.ignored_modules = new Hash(); - var function_token_processor = this.tokenProcessors.get("FunctionTokenProcessor"); + var function_token_processor = this.token_processors.get("FunctionTokenProcessor"); var function_tokens_found = new Hash(); var tokens_to_ignore = new Array>(); @@ -120,7 +124,13 @@ class CodeParser { new_tokens_to_ignore.shift(); var tokens_to_ignore_hash = new Hash(); for (token in new_tokens_to_ignore) { - tokens_to_ignore_hash.set(token, true); + if (token.charAt(0) == "@") { + if (token.toLowerCase() != "@php") { + this.ignored_modules.set(token.substr(1), true); + } + } else { + tokens_to_ignore_hash.set(token, true); + } } tokens_to_ignore.push(tokens_to_ignore_hash); } diff --git a/src/CodeVersionInformation.hx b/src/CodeVersionInformation.hx index 364ed3a..b5b02f7 100644 --- a/src/CodeVersionInformation.hx +++ b/src/CodeVersionInformation.hx @@ -106,27 +106,24 @@ class CodeVersionInformation { var version_lists = new Hash>(); var version_match = ~/^([^\ ]+) (.*)$/; for (part in s.split(", ")) { - if (version_match.match(part)) { - var source = version_match.matched(1); - if (!version_lists.exists(source)) { - version_lists.set(source, new Array()); - } - var tmp = version_lists.get(source); - tmp.push(version_match.matched(2)); - version_lists.set(source, tmp); + var parts = breakdown_php_version_string(part); + var source = parts[0]; + if (!version_lists.exists(source)) { + version_lists.set(source, new Array()); } + var tmp = version_lists.get(source); + tmp.push(parts[1]); + version_lists.set(source, tmp); } var final_versions = new Hash(); for (source in version_lists.keys()) { - var tmp = version_lists.get(source); - tmp.sort(CodeVersionInformation.version_compare); - final_versions.set(source, tmp.join(", ")); + final_versions.set(source, CodeVersionInformation.get_lowest_version(version_lists.get(source))); } return final_versions; } - public function new(results : Array) { + public function new(results : Array, ?ignored_modules : Hash) { var start_minimum_versions = new Hash>(); var start_maximum_versions = new Hash>(); @@ -140,22 +137,29 @@ class CodeVersionInformation { if (version_string_info.length > 0) { var source = version_string_info[0]; - if (!internal_minimum_version.exists(source)) { - internal_minimum_version.set(source, new Array()); + var ok_to_use = true; + if (ignored_modules != null) { + ok_to_use = !ignored_modules.exists(source); } - var version_info = internal_minimum_version.get(source); - version_info.push(version_string_info[1]); - internal_minimum_version.set(source, version_info); - var is_lower_than = get_version_lower_than(part); - if (is_lower_than != null) { - if (!internal_maximum_version.exists(source)) { - internal_maximum_version.set(source, new Array()); + if (ok_to_use) { + if (!internal_minimum_version.exists(source)) { + internal_minimum_version.set(source, new Array()); } + var version_info = internal_minimum_version.get(source); + version_info.push(version_string_info[1]); + internal_minimum_version.set(source, version_info); - var versions = internal_maximum_version.get(source); - versions.push(is_lower_than); - internal_maximum_version.set(source, versions); + var is_lower_than = get_version_lower_than(part); + if (is_lower_than != null) { + if (!internal_maximum_version.exists(source)) { + internal_maximum_version.set(source, new Array()); + } + + var versions = internal_maximum_version.get(source); + versions.push(is_lower_than); + internal_maximum_version.set(source, versions); + } } } } diff --git a/src/JavaScriptTarget.hx b/src/JavaScriptTarget.hx index 18a3161..14463b8 100644 --- a/src/JavaScriptTarget.hx +++ b/src/JavaScriptTarget.hx @@ -2,6 +2,7 @@ class JavaScriptTarget { static public var code_parser : CodeParser; static public var current_results : Array; static public var show_only_modules : Hash; + static public var ignored_modules : Hash; static public function main() { var function_token = new FunctionToken("a","a"); @@ -10,6 +11,7 @@ class JavaScriptTarget { code_parser.loadProcessorsFromResources(); show_only_modules = new Hash(); + ignored_modules = new Hash(); #if js var loading_div = js.Lib.document.getElementById("loading"); @@ -22,6 +24,7 @@ class JavaScriptTarget { static public function get_results(s : String) { current_results = code_parser.parse(s); + ignored_modules = code_parser.ignored_modules; } static public function change_result(index_id : Int, state : Bool) : Bool { @@ -39,6 +42,17 @@ class JavaScriptTarget { show_only_modules.set(module, !show_only_modules.get(module)); } + static public function change_module_ignore(module : String, state : Bool) { + ignored_modules.set(module, state); + } + + static public function toggle_ignore_module(module: String) { + if (!ignored_modules.exists(module)) { + ignored_modules.set(module, false); + } + ignored_modules.set(module, !ignored_modules.get(module)); + } + #if js static public function change_result_and_redraw(result_checkbox : Dynamic) { var index_id_search = ~/^result-enabled-([0-9]+)$/; @@ -51,12 +65,16 @@ class JavaScriptTarget { } static public function display_version_information() { - var version_info = new CodeVersionInformation(current_results); + var version_info = new CodeVersionInformation(current_results, ignored_modules); - var output = "Your code in requires the following minimum PHP & PECL module versions:
    "; + var output = "Your code in requires the following minimum PHP & PECL module versions:"; var minimum = version_info.final_versions.get("minimum"); + output += "
    "; + + output += "
      "; + for (module in minimum.keys()) { output += "
    • " + module + ": " + minimum.get(module) + "
    • "; } @@ -80,8 +98,6 @@ class JavaScriptTarget { output += "

      This code may not run!

      "; } - output += ""; - output += ""; output += ""; @@ -104,6 +120,7 @@ class JavaScriptTarget { for (result in current_results) { var ok_to_show = true; var modules_check_out = true; + var any_visible_modules = false; if (!result.is_enabled) { ignored_tokens.push(result.token); } @@ -116,7 +133,16 @@ class JavaScriptTarget { } } + for (module in max_versions.keys()) { + if (ignored_modules.exists(module)) { + if (!ignored_modules.get(module)) { any_visible_modules = true; } + } else { + any_visible_modules = true; + } + } + if (modules_check_out) { ok_to_show = true; } + if (!any_visible_modules) { ok_to_show = false; } if (ok_to_show) { var result_class = (result.is_enabled ? "enabled" : "disabled"); @@ -174,5 +200,10 @@ class JavaScriptTarget { JavaScriptTarget.toggle_module(module); JavaScriptTarget.display_version_information(); } + + static public function toggle_ignore_module_and_redraw(module : String) { + JavaScriptTarget.toggle_ignore_module(module); + JavaScriptTarget.display_version_information(); + } #end } \ No newline at end of file diff --git a/src/TestCodeParser.hx b/src/TestCodeParser.hx index 9823100..2c44420 100644 --- a/src/TestCodeParser.hx +++ b/src/TestCodeParser.hx @@ -5,14 +5,16 @@ class TestCodeParser extends haxe.unit.TestCase { [ "this is my array_shift() json_encode() cpdf_arc()", "3", "{minimum => {PHP => 5.2.0, json => 1.2.0}, maximum => {PHP => 5.0.5}}" ], [ "array_shift()", "1", "{minimum => {PHP => 4}, maximum => {}}" ], [ "//harmonious json_encode\narray_shift() json_encode()\n//harmonious_end", "1", "{minimum => {PHP => 4}, maximum => {}}" ], - [ "//harmonious json_encode\narray_shift() json_encode()\n//harmonious_end\njson_encode()", "2", "{minimum => {PHP => 5.2.0, json => 1.2.0}, maximum => {}}" ] + [ "//harmonious json_encode\narray_shift() json_encode()\n//harmonious_end\njson_encode()", "2", "{minimum => {PHP => 5.2.0, json => 1.2.0}, maximum => {}}" ], + [ "//harmonious @json\narray_shift() json_encode()\n//harmonious_end\njson_encode()", "2", "{minimum => {PHP => 5.2.0}, maximum => {}}" ], + [ "//harmonious @PHP\narray_shift()", "1", "{minimum => {PHP => 4}, maximum => {}}" ] ]; #if neko function testCodeParserLoadTokens() { var p = new CodeParser(); p.loadProcessorsFromDisk(); - assertTrue(p.tokenProcessors.exists("FunctionTokenProcessor")); + assertTrue(p.token_processors.exists("FunctionTokenProcessor")); } function testProcessCode() { @@ -21,8 +23,9 @@ class TestCodeParser extends haxe.unit.TestCase { for (code in test_code) { var result = p.parse(code[0]); + var ignored_modules = p.ignored_modules; assertEquals(Std.parseInt(code[1]), result.length); - var code_version_info = new CodeVersionInformation(result); + var code_version_info = new CodeVersionInformation(result, ignored_modules); assertEquals(code[2], code_version_info.final_versions.toString()); } } diff --git a/src/TestCodeVersionInformation.hx b/src/TestCodeVersionInformation.hx index f04dd38..27b1c76 100644 --- a/src/TestCodeVersionInformation.hx +++ b/src/TestCodeVersionInformation.hx @@ -70,8 +70,8 @@ class TestCodeVersionInformation extends haxe.unit.TestCase { function testGetVersionStringSplit() { assertEquals("{xmlwriter => 2.0.4, PHP => 4}", CodeVersionInformation.split_version_string("PHP 4, xmlwriter 2.0.4").toString()); - assertEquals("{xmlwriter => 2.0.4, PHP => 4 >= 4.0.3}", CodeVersionInformation.split_version_string("PHP 4 >= 4.0.3, xmlwriter 2.0.4").toString()); - assertEquals("{PHP => 4, 5}", CodeVersionInformation.split_version_string("PHP 5, PHP 4").toString()); + assertEquals("{xmlwriter => 2.0.4, PHP => 4.0.3}", CodeVersionInformation.split_version_string("PHP 4 >= 4.0.3, xmlwriter 2.0.4").toString()); + assertEquals("{PHP => 4}", CodeVersionInformation.split_version_string("PHP 5, PHP 4").toString()); } function testGetModuleInformation() { @@ -83,4 +83,17 @@ class TestCodeVersionInformation extends haxe.unit.TestCase { assertEquals("[PHP, xmod, zmod]", v.all_modules.toString()); } + + function testIgnoreModules() { + var valid_results = [ + new Result(ResultType.Function, "one", "PHP 4, zmod 5"), + new Result(ResultType.Function, "two", "PHP 4 >= 4.0.6, xmod 5"), + new Result(ResultType.Function, "three", "zmod 5"), + ]; + var ignored_modules = new Hash(); + ignored_modules.set("xmod", true); + var v = new CodeVersionInformation(valid_results, ignored_modules); + + assertEquals("[PHP, zmod]", v.all_modules.toString()); + } } \ No newline at end of file diff --git a/src/TestJavaScriptTarget.hx b/src/TestJavaScriptTarget.hx index 59aeb1d..9aa083c 100644 --- a/src/TestJavaScriptTarget.hx +++ b/src/TestJavaScriptTarget.hx @@ -14,5 +14,11 @@ class TestJavaScriptTarget extends haxe.unit.TestCase { assertEquals("{}", JavaScriptTarget.show_only_modules.toString()); JavaScriptTarget.toggle_module("zip"); assertEquals("{zip => true}", JavaScriptTarget.show_only_modules.toString()); + + assertEquals("{}", JavaScriptTarget.ignored_modules.toString()); + JavaScriptTarget.change_module_ignore("zip", true); + assertEquals("{zip => true}", JavaScriptTarget.ignored_modules.toString()); + JavaScriptTarget.change_module_ignore("zip", false); + assertEquals("{zip => false}", JavaScriptTarget.ignored_modules.toString()); } } \ No newline at end of file
      TokenIgnore?