diff --git a/.gitignore b/.gitignore index 69569d9c..37ef4a1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,7 @@ WEB-INF/* -litepost/* -mxunit/* wirebox/* -tests/ci/results -tests/ci/results/* +testbox/* +tests/results/ .project settings.xml .settings/org.eclipse.core.resources.prefs @@ -11,8 +9,4 @@ settings.xml *.iml *.ipr *.idea -.ant-targets-build.xml run-tests.sh -/examples/6helloclojure/target/stale/extract-native.dependencies -/taskmanager/ -/server.json diff --git a/.travis.yml b/.travis.yml index e5abee62..21bf0d45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,35 @@ language: java + +sudo: required + env: matrix: - - PLATFORM=acf10-linux64 - - PLATFORM=railo42beta - - PLATFORM=railo41 + - ENGINE=lucee@4.5 + - ENGINE=lucee@5 + - ENGINE=adobe@2016 + - ENGINE=adobe@11 + - ENGINE=adobe@10 + +cache: + directories: + - $HOME/.CommandBox + +before_install: + - sudo apt-key adv --keyserver keys.gnupg.net --recv 6DA70622 + - sudo echo "deb http://downloads.ortussolutions.com/debs/noarch /" | sudo tee -a + /etc/apt/sources.list.d/commandbox.list + +install: + - sudo apt-get update && sudo apt-get --assume-yes install commandbox + - box install + +before_script: + - box server start cfengine=$ENGINE port=8500 openbrowser=false + +script: > + testResults="echo $(box testbox run reporter=mintext)"; + echo "$testResults"; + if grep -i "\[Failures: [1-9][0-9]\?[0-9]\?\]\|\[Errors: [1-9][0-9]\?[0-9]\?\]\|]*>\|]*>" <<< $testResults; then exit 1; fi notifications: webhooks: @@ -12,6 +38,3 @@ notifications: on_success: change # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always on_start: false # default: false - -install: ant -Dsource=remote -Dwork.dir=$HOME/work -Dbuild.dir=$TRAVIS_BUILD_DIR -Dplatform=$PLATFORM install-ci-deps -script: ant -Dsource=remote -Dwork.dir=$HOME/work -Dbuild.dir=$TRAVIS_BUILD_DIR -Dplatform=$PLATFORM test-ci diff --git a/Application.cfc b/Application.cfc index efa4ba9e..149e6b60 100644 --- a/Application.cfc +++ b/Application.cfc @@ -18,7 +18,8 @@ component { // create your FW/1 application: request._framework_one = new framework.one( { trace = true, - base = getDirectoryFromPath( CGI.SCRIPT_NAME ) + missingview = 'main.missingview', + base = getDirectoryFromPath( CGI.SCRIPT_NAME ) .replaceFirst( getContextRoot(), '' ) & 'introduction' } ); diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cf78256b..9c82ba1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ Contributing to Framework One (FW/1, DI/1, AOP/1) == Please note that in order to encourage more people to get involved with Framework One, we have adopted a [Code of Conduct](CODE_OF_CONDUCT.md) so that _everyone_ should feel welcome and safe when getting involved with any aspect of the Framework One community. -All development happens in the main [Framework One repository](https://github.com/framework-one/fw1) on the **develop** branch. Feel free to fork the repo and submit Pull Requests on the **develop** branch. You can also open issues there to discuss potential enhancements etc. +All development happens in the main [Framework One repository](https://github.com/framework-one/fw1) on the **develop** branch. Feel free to fork the repo and submit Pull Requests on the **develop** branch. You can also open issues there to discuss potential enhancements etc. You can also discuss bugs and enhancements on [Gitter](https://gitter.im/framework-one/fw1) or [Slack](https://cfml.slack.com/messages/fw1/). You can sign into Gitter directly using your GitHub credentials. For Slack, you'll need to [request an account](http://cfml-slack.herokuapp.com/). Pull Requests that contain new/updated tests for the bug fix / enhancement will be looked on more favorably than those that do not contain fixes. Travis-CI automatically runs the test suite for Pull Requests which helps us be confident that the Pull Request is "good". diff --git a/LICENSE b/LICENSE index 210b6d6f..2c308fc1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2016 Sean Corfield (see individual files for any +Copyright (c) 2009-2017 Sean Corfield (see individual files for any additional copyright holders) Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/README.md b/README.md index c46a3c73..a0251ab9 100644 --- a/README.md +++ b/README.md @@ -23,28 +23,24 @@ Please read the [Framework One Code of Conduct](CODE_OF_CONDUCT.md) - we want FW # Running the Tests -The Ant `build.xml` file is primarily designed to be used by Travis to run the tests automatically, but it is possible to run the tests locally, with some setup: +FW/1 is setup to run tests on [Travis CI](https://travis-ci.org/framework-one/fw1) using the `.travis.yml` file. -* This FW/1 directory needs to be a web root for some test domain on your local machine. I have `fw1.local` setup to resolve to this folder. -* You'll need MXUnit installed and accessible via `/mxunit` for the test domain you use for this project. You can install MXUnit into this FW/1 directory if you want - `mxunit/*` is on the `.gitignore` list. +To run tests manually, you'll need [CommandBox](https://www.ortussolutions.com/products/commandbox) installed. -You can run the build locally using a variant of this command (all on one line): +Then run `box install` once to install the dependencies (TestBox is the only one currently). - ant -Dplatform=railo41 -Dtest.path.root=/Developer/workspace/fw1 \ - -Dcontext.root= -Dserver.name=fw1.local -Dserver.port=8080 \ - run-tests-mxunit +Then start a server on port 8500 with your choice of CFML engine, e.g., -See the `run-tests-example.sh` file for a template (for Mac/Linux). + box server start cfengine=lucee@5 port=8500 -* `platform` needs to be set just to satisfy the build script it doesn't affect anything (so use `railo41` even if you're on ACF or a different version of Railo) -* `test.path.root` should be the filesystem path to this directory, i.e., the web root for the FW/1 project. -* `context.root` should probably be empty (unless you are using a named web application context) -* `server.name` should be the test domain you have configured -* `server.port` should be the port on which you access that test domain -* `run-tests-mxunit` is the actual Ant task that does the testing +This will open a browser, running the FW/1 "Introduction" app. + +You can then run the tests: + + box testbox run reporter=mintext # Copyright and License -Copyright (c) 2009-2016 Sean Corfield (and others -- see individual files for additional copyright holders). All rights reserved. +Copyright (c) 2009-2017 Sean Corfield (and others -- see individual files for additional copyright holders). All rights reserved. The use and distribution terms for this software are covered by the Apache Software License 2.0 (http://www.apache.org/licenses/LICENSE-2.0) which can also be found in the file LICENSE at the root of this distribution and in individual licensed files. By using this software in any fashion, you are agreeing to be bound by the terms of this license. You must not remove this notice, or any other, from this software. diff --git a/box.json b/box.json index 181345cc..12209ba0 100644 --- a/box.json +++ b/box.json @@ -1,32 +1,66 @@ { - "name" : "Framework One", - "slug" : "fw1", - "version" : "4.0.0", - "author" : "Sean Corfield, Marcin Szczepanski, Ryan Cogswell", - "location" : "https://github.com/framework-one/fw1/archive/v4.0.0.zip", - "createPackageDirectory" : true, - "packageDirectory" : "framework", - "Homepage" : "http://framework-one.github.io/", - "Documentation" : "http://framework-one.github.io/documentation/", - "Repository" : { - "type" : "git", "URL" : "https://github.com/framework-one/fw1.git" - }, - "Bugs" : "https://github.com/framework-one/fw1/issues", - "shortDescription" : "FW/1 - Framework One - is a family of small, lightweight, convention-over-configuration frameworks, primarily for CFML.", - "description" : "FW/1 - Framework One - is a family of small, lightweight, convention-over-configuration frameworks, primarily for CFML. FW/1 itself provides MVC, DI/1 provides dependency injection (a.k.a. inversion of control), and AOP/1 provides aspect-oriented programming features on top of DI/1.", - "instructions" : "http://framework-one.github.io/documentation/", - "changelog" : "https://github.com/framework-one/fw1/commits/master", - "type" : "mvc", - "keywords" : [ "fw1", "framework one", "mvc", "conventions" ], - "private" : "false", - "engines" : [ - { "type" : "railo", "version" : ">=4.1.x" }, - { "type" : "lucee", "version" : ">=4.5.x" }, - { "type" : "adobe", "version" : ">=10.0.x" } + "name":"Framework One", + "slug":"fw1", + "version":"4.1.0", + "author":"Sean Corfield, Marcin Szczepanski, Ryan Cogswell", + "location":"https://github.com/framework-one/fw1/archive/v4.1.0.zip", + "createPackageDirectory":true, + "packageDirectory":"framework", + "Homepage":"http://framework-one.github.io/", + "Documentation":"http://framework-one.github.io/documentation/", + "Repository":{ + "type":"git", + "URL":"https://github.com/framework-one/fw1.git" + }, + "Bugs":"https://github.com/framework-one/fw1/issues", + "shortDescription":"FW/1 - Framework One - is a family of small, lightweight, convention-over-configuration frameworks, primarily for CFML.", + "description":"FW/1 - Framework One - is a family of small, lightweight, convention-over-configuration frameworks, primarily for CFML. FW/1 itself provides MVC, DI/1 provides dependency injection (a.k.a. inversion of control), and AOP/1 provides aspect-oriented programming features on top of DI/1.", + "instructions":"http://framework-one.github.io/documentation/", + "changelog":"https://github.com/framework-one/fw1/commits/master", + "type":"mvc", + "keywords":[ + "fw1", + "framework one", + "mvc", + "conventions" ], - "License" : [ - { "type" : "Apache 2.0", "URL" : "http://www.apache.org/licenses/LICENSE-2.0" } + "private":"false", + "engines":[ + { + "type":"railo", + "version":">=4.1.x" + }, + { + "type":"lucee", + "version":">=4.5.x" + }, + { + "type":"adobe", + "version":">=10.0.x" + } ], - "Contributors" : [ {"name": "Contributors List", "url": "https://github.com/framework-one/fw1/graphs/contributors"} ], - "ignore" : [ ] + "License":[ + { + "type":"Apache 2.0", + "URL":"http://www.apache.org/licenses/LICENSE-2.0" + } + ], + "Contributors":[ + { + "name":"Contributors List", + "url":"https://github.com/framework-one/fw1/graphs/contributors" + } + ], + "ignore":[ + + ], + "devDependencies":{ + "testbox":"^2.3.0+00044" + }, + "installPaths":{ + "testbox":"testbox" + }, + "testbox":{ + "runner":"http://localhost:8500/tests/runner.cfm" + } } diff --git a/build.xml b/build.xml deleted file mode 100644 index a6503415..00000000 --- a/build.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Unkown platform ${platform} for source ${source}. - -Valid values are: - railo41 - railo41-osx - railo42beta - acf10-linux32 - acf10-linux64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/Application.cfc b/examples/Application.cfc index 7e692efd..fd18a9f3 100644 --- a/examples/Application.cfc +++ b/examples/Application.cfc @@ -18,10 +18,7 @@ component { // create your FW/1 application: request._framework_one = new framework.one( { SESOmitIndex = true, - diComponent = "framework.ioclj", diLocations = [ - // must provide path to project.clj in Clojure example: - getDirectoryFromPath( CGI.SCRIPT_NAME ) & "/subsystems/6helloclojure", "model", "controllers", "beans", "services" // to account for the variety of D/I locations in our examples // that allows all our subsystems to automatically have their own bean factory with the base factory as parent ], diff --git a/examples/layouts/default.cfm b/examples/layouts/default.cfm index d0f85065..c7bf3d39 100644 --- a/examples/layouts/default.cfm +++ b/examples/layouts/default.cfm @@ -12,7 +12,7 @@

Examples Home

diff --git a/examples/mustache/Application.cfc b/examples/mustache/Application.cfc new file mode 100644 index 00000000..f194aa7a --- /dev/null +++ b/examples/mustache/Application.cfc @@ -0,0 +1,36 @@ +component extends=framework.one { + + variables.mustacheJAR = expandPath( "compiler-0.9.1.jar" ); + this.javaSettings.loadPaths = [ variables.mustacheJAR ]; + + function setupApplication() { + var mustacheFactory = "com.github.mustachejava.DefaultMustacheFactory"; + var viewRoot = expandPath( "/" ); + application.mustache = createObject( + "java", mustacheFactory + ).init( + createObject( "java", "java.io.File" ).init( viewRoot ) + ); + } + + function setupView( rc ) { + variables.mustacheProxies = makeMethodProxies( [ "buildURL", "view" ] ); + } + + // we must override this to change the file extension that FW/1 looks for: + public string function customizeViewOrLayoutPath( struct pathInfo, string type, string fullPath ) { + return '#pathInfo.base##type#s/#pathInfo.path#.html'; + } + + public any function customTemplateEngine( string type, string path, struct scope ) { + // so mustache can see these functions: + scope.fw1 = variables.mustacheProxies; + // compile & execute the template: + var template = application.mustache.compile( path ); + var writer = createObject( "java", "java.io.StringWriter" ).init(); + template.execute( writer, [ scope ] ); + writer.flush(); + return writer.toString(); + } + +} diff --git a/examples/mustache/compiler-0.9.1.jar b/examples/mustache/compiler-0.9.1.jar new file mode 100644 index 00000000..c187cfd0 Binary files /dev/null and b/examples/mustache/compiler-0.9.1.jar differ diff --git a/examples/mustache/controllers/main.cfc b/examples/mustache/controllers/main.cfc new file mode 100644 index 00000000..6ac82bf5 --- /dev/null +++ b/examples/mustache/controllers/main.cfc @@ -0,0 +1,12 @@ +component { + + function default( rc ) { + rc.numbers = [1,2,3,4]; + rc.productversion = + server.coldfusion.productname & " " & + ( structKeyExists( server, "lucee" ) ? + server.lucee.version & " / " : "" ) & + server.coldfusion.productversion; + } + +} diff --git a/examples/subsystems/6helloclojure/index.cfm b/examples/mustache/index.cfm similarity index 100% rename from examples/subsystems/6helloclojure/index.cfm rename to examples/mustache/index.cfm diff --git a/examples/mustache/layouts/default.html b/examples/mustache/layouts/default.html new file mode 100644 index 00000000..add46a74 --- /dev/null +++ b/examples/mustache/layouts/default.html @@ -0,0 +1,14 @@ + + + Mustache Layout + + +

+ We use the triple mustache delimiters around body so that the HTML + it contains is not escaped. +

+
+ {{{body}}} +
+ + diff --git a/examples/mustache/views/main/default.html b/examples/mustache/views/main/default.html new file mode 100644 index 00000000..793fb87f --- /dev/null +++ b/examples/mustache/views/main/default.html @@ -0,0 +1,11 @@ +

Hello from Mustache!

+

Your name is {{rc.name}}!

+ +

Call a FW/1 function to generate a link: Linked Page!

+

Load a fragment via Mustache partial (page-relative): {{> page/fragment}}

+

Load a fragment via FW/1's view (views-root-relative): {{#fw1.view}}main/page/fragment{{/fw1.view}}

+

Powered by {{rc.productversion}}.

diff --git a/examples/mustache/views/main/page/fragment.html b/examples/mustache/views/main/page/fragment.html new file mode 100644 index 00000000..5c05f52a --- /dev/null +++ b/examples/mustache/views/main/page/fragment.html @@ -0,0 +1 @@ +This is a page fragment! diff --git a/examples/rest/Application.cfc b/examples/rest/Application.cfc new file mode 100644 index 00000000..c53f354c --- /dev/null +++ b/examples/rest/Application.cfc @@ -0,0 +1,34 @@ +component { + this.name = 'fw1-examples-rest'; + this.mappings[ '/framework' ] = expandPath( '../framework' ); + + function _get_framework_one() { + if ( !structKeyExists( request, '_framework_one' ) ) { + request._framework_one = new framework.one( { + decodeRequestBody = true, + reloadApplicationOnEveryRequest = true + } ); + } + return request._framework_one; + } + + // delegation of lifecycle methods to FW/1: + function onApplicationStart() { + return _get_framework_one().onApplicationStart(); + } + function onError( exception, event ) { + return _get_framework_one().onError( exception, event ); + } + function onRequest( targetPath ) { + return _get_framework_one().onRequest( targetPath ); + } + function onRequestEnd() { + return _get_framework_one().onRequestEnd(); + } + function onRequestStart( targetPath ) { + return _get_framework_one().onRequestStart( targetPath ); + } + function onSessionStart() { + return _get_framework_one().onSessionStart(); + } +} diff --git a/examples/rest/controllers/main.cfc b/examples/rest/controllers/main.cfc new file mode 100644 index 00000000..1fd6e1b3 --- /dev/null +++ b/examples/rest/controllers/main.cfc @@ -0,0 +1,35 @@ +component { + + function init( any fw ) { + variables.fw = fw; + return this; + } + + function patch( struct rc, struct headers ) { + var response = { + "method": "PATCH", + "multi": rc.multi, + "single": rc.single + }; + variables.fw.renderData().type( 'json' ).data( response ); + } + + function post( struct rc, struct headers ) { + var response = { + "method": "POST", + "multi": rc.multi, + "single": rc.single + }; + variables.fw.renderData().type( 'json' ).data( response ); + } + + function put( struct rc, struct headers ) { + var response = { + "method": "PUT", + "multi": rc.multi, + "single": rc.single + }; + variables.fw.renderData().type( 'json' ).data( response ); + } + +} diff --git a/examples/rest/index.cfm b/examples/rest/index.cfm new file mode 100644 index 00000000..f184d0f5 --- /dev/null +++ b/examples/rest/index.cfm @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/rest/views/main/default.cfm b/examples/rest/views/main/default.cfm new file mode 100644 index 00000000..824936d1 --- /dev/null +++ b/examples/rest/views/main/default.cfm @@ -0,0 +1 @@ +This rest example is used by the tests to assert that data is decoded as expected \ No newline at end of file diff --git a/examples/subsystems/6helloclojure/.gitignore b/examples/subsystems/6helloclojure/.gitignore deleted file mode 100644 index c53038ec..00000000 --- a/examples/subsystems/6helloclojure/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -/target -/classes -/checkouts -pom.xml -pom.xml.asc -*.jar -*.class -/.lein-* -/.nrepl-port -.hgignore -.hg/ diff --git a/examples/subsystems/6helloclojure/Application.cfc b/examples/subsystems/6helloclojure/Application.cfc deleted file mode 100644 index 9ecb4797..00000000 --- a/examples/subsystems/6helloclojure/Application.cfc +++ /dev/null @@ -1,61 +0,0 @@ -component { - // copy this to your application root to use as your Application.cfc - // or incorporate the logic below into your existing Application.cfc - - // you can provide a specific application name if you want: - this.name = hash( getBaseTemplatePath() ); - - // any other application settings: - this.sessionManagement = true; - - // set up per-application mappings as needed: - this.mappings[ '/framework' ] = expandPath( '../../../framework' ); - // this.mappings[ '/app' ] expandPath( '../path/to/app' ); - - function _get_framework_one() { - if ( !structKeyExists( request, '_framework_one' ) ) { - - // create your FW/1 application: - request._framework_one = new MyApplication({ - trace : true, - diComponent : "framework.ioclj", - diLocations : getDirectoryFromPath( CGI.SCRIPT_NAME ) - }); - - // you can specify FW/1 configuration as an argument: - // request._framework_one = new framework.one({ - // base : '/app', - // trace : true - // }); - - // if you need to override extension points, use - // MyApplication.cfc for those and then do: - // request._framework_one = new MyApplication({ - // base : '/app', - // trace : true - // }); - - } - return request._framework_one; - } - - // delegation of lifecycle methods to FW/1: - function onApplicationStart() { - return _get_framework_one().onApplicationStart(); - } - function onError( exception, event ) { - return _get_framework_one().onError( exception, event ); - } - function onRequest( targetPath ) { - return _get_framework_one().onRequest( targetPath ); - } - function onRequestEnd() { - return _get_framework_one().onRequestEnd(); - } - function onRequestStart( targetPath ) { - return _get_framework_one().onRequestStart( targetPath ); - } - function onSessionStart() { - return _get_framework_one().onSessionStart(); - } -} diff --git a/examples/subsystems/6helloclojure/LICENSE b/examples/subsystems/6helloclojure/LICENSE deleted file mode 100644 index 7689f30e..00000000 --- a/examples/subsystems/6helloclojure/LICENSE +++ /dev/null @@ -1,214 +0,0 @@ -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC -LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM -CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and -documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are -distributed by that particular Contributor. A Contribution 'originates' from -a Contributor if it was added to the Program by such Contributor itself or -anyone acting on such Contributor's behalf. Contributions do not include -additions to the Program which: (i) are separate modules of software -distributed in conjunction with the Program under their own license -agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are -necessarily infringed by the use or sale of its Contribution alone or when -combined with the Program. - -"Program" means the Contributions distributed in accordance with this -Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, -including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free copyright license to -reproduce, prepare derivative works of, publicly display, publicly perform, -distribute and sublicense the Contribution of such Contributor, if any, and -such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free patent license under -Licensed Patents to make, use, sell, offer to sell, import and otherwise -transfer the Contribution of such Contributor, if any, in source code and -object code form. This patent license shall apply to the combination of the -Contribution and the Program if, at the time the Contribution is added by the -Contributor, such addition of the Contribution causes such combination to be -covered by the Licensed Patents. The patent license shall not apply to any -other combinations which include the Contribution. No hardware per se is -licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses -to its Contributions set forth herein, no assurances are provided by any -Contributor that the Program does not infringe the patent or other -intellectual property rights of any other entity. Each Contributor disclaims -any liability to Recipient for claims brought by any other entity based on -infringement of intellectual property rights or otherwise. As a condition to -exercising the rights and licenses granted hereunder, each Recipient hereby -assumes sole responsibility to secure any other intellectual property rights -needed, if any. For example, if a third party patent license is required to -allow Recipient to distribute the Program, it is Recipient's responsibility -to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient -copyright rights in its Contribution, if any, to grant the copyright license -set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under -its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title -and non-infringement, and implied warranties or conditions of merchantability -and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for -damages, including direct, indirect, special, incidental and consequential -damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered -by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such -Contributor, and informs licensees how to obtain it in a reasonable manner on -or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within -the Program. - -Each Contributor must identify itself as the originator of its Contribution, -if any, in a manner that reasonably allows subsequent Recipients to identify -the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with -respect to end users, business partners and the like. While this license is -intended to facilitate the commercial use of the Program, the Contributor who -includes the Program in a commercial product offering should do so in a -manner which does not create potential liability for other Contributors. -Therefore, if a Contributor includes the Program in a commercial product -offering, such Contributor ("Commercial Contributor") hereby agrees to defend -and indemnify every other Contributor ("Indemnified Contributor") against any -losses, damages and costs (collectively "Losses") arising from claims, -lawsuits and other legal actions brought by a third party against the -Indemnified Contributor to the extent caused by the acts or omissions of such -Commercial Contributor in connection with its distribution of the Program in -a commercial product offering. The obligations in this section do not apply -to any claims or Losses relating to any actual or alleged intellectual -property infringement. In order to qualify, an Indemnified Contributor must: -a) promptly notify the Commercial Contributor in writing of such claim, and -b) allow the Commercial Contributor tocontrol, and cooperate with the -Commercial Contributor in, the defense and any related settlement -negotiations. The Indemnified Contributor may participate in any such claim -at its own expense. - -For example, a Contributor might include the Program in a commercial product -offering, Product X. That Contributor is then a Commercial Contributor. If -that Commercial Contributor then makes performance claims, or offers -warranties related to Product X, those performance claims and warranties are -such Commercial Contributor's responsibility alone. Under this section, the -Commercial Contributor would have to defend claims against the other -Contributors related to those performance claims and warranties, and if a -court requires any other Contributor to pay any damages as a result, the -Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON -AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER -EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR -CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A -PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the -appropriateness of using and distributing the Program and assumes all risks -associated with its exercise of rights under this Agreement , including but -not limited to the risks and costs of program errors, compliance with -applicable laws, damage to or loss of data, programs or equipment, and -unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY -CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION -LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE -EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under -applicable law, it shall not affect the validity or enforceability of the -remainder of the terms of this Agreement, and without further action by the -parties hereto, such provision shall be reformed to the minimum extent -necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Program itself -(excluding combinations of the Program with other software or hardware) -infringes such Recipient's patent(s), then such Recipient's rights granted -under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to -comply with any of the material terms or conditions of this Agreement and -does not cure such failure in a reasonable period of time after becoming -aware of such noncompliance. If all Recipient's rights under this Agreement -terminate, Recipient agrees to cease use and distribution of the Program as -soon as reasonably practicable. However, Recipient's obligations under this -Agreement and any licenses granted by Recipient relating to the Program shall -continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in -order to avoid inconsistency the Agreement is copyrighted and may only be -modified in the following manner. The Agreement Steward reserves the right to -publish new versions (including revisions) of this Agreement from time to -time. No one other than the Agreement Steward has the right to modify this -Agreement. The Eclipse Foundation is the initial Agreement Steward. The -Eclipse Foundation may assign the responsibility to serve as the Agreement -Steward to a suitable separate entity. Each new version of the Agreement will -be given a distinguishing version number. The Program (including -Contributions) may always be distributed subject to the version of the -Agreement under which it was received. In addition, after a new version of -the Agreement is published, Contributor may elect to distribute the Program -(including its Contributions) under the new version. Except as expressly -stated in Sections 2(a) and 2(b) above, Recipient receives no rights or -licenses to the intellectual property of any Contributor under this -Agreement, whether expressly, by implication, estoppel or otherwise. All -rights in the Program not expressly granted under this Agreement are -reserved. - -This Agreement is governed by the laws of the State of New York and the -intellectual property laws of the United States of America. No party to this -Agreement will bring a legal action under this Agreement more than one year -after the cause of action arose. Each party waives its rights to a jury trial -in any resulting litigation. diff --git a/examples/subsystems/6helloclojure/MyApplication.cfc b/examples/subsystems/6helloclojure/MyApplication.cfc deleted file mode 100644 index eb99463f..00000000 --- a/examples/subsystems/6helloclojure/MyApplication.cfc +++ /dev/null @@ -1,8 +0,0 @@ -component extends=framework.one { - function setupRequest() { - // reload Clojure when FW/1 is reloaded: - if ( isFrameworkReloadRequest() ) { - getBeanFactory().reload( "all" ); - } - } -} diff --git a/examples/subsystems/6helloclojure/README.md b/examples/subsystems/6helloclojure/README.md deleted file mode 100644 index 66aab0d0..00000000 --- a/examples/subsystems/6helloclojure/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# hello - -A Clojure library designed to ... well, that part is up to you. - -## Usage - -FIXME - -## License - -Copyright © 2015 FIXME - -Distributed under the Eclipse Public License either version 1.0 or (at -your option) any later version. diff --git a/examples/subsystems/6helloclojure/boot.properties b/examples/subsystems/6helloclojure/boot.properties deleted file mode 100644 index 421b1965..00000000 --- a/examples/subsystems/6helloclojure/boot.properties +++ /dev/null @@ -1,6 +0,0 @@ -#http://boot-clj.com -#Mon Dec 21 11:44:14 PST 2015 -BOOT_CLOJURE_NAME=org.clojure/clojure -BOOT_CLOJURE_VERSION=1.7.0 -BOOT_VERSION=2.5.2 -BOOT_EMIT_TARGET=no diff --git a/examples/subsystems/6helloclojure/build.boot b/examples/subsystems/6helloclojure/build.boot deleted file mode 100644 index 29581d13..00000000 --- a/examples/subsystems/6helloclojure/build.boot +++ /dev/null @@ -1,9 +0,0 @@ -;; very minimal Boot build file: for use with cfmljure we do not -;; need any pom / jar information, just the dependencies and a -;; matching boot.properties file -(set-env! :resource-paths #{"src"} - :source-paths #{"test"} - :dependencies '[[org.clojure/clojure "1.7.0"] - [adzerk/boot-test "1.0.7"]]) - -(require '[adzerk.boot-test :refer [test]]) diff --git a/examples/subsystems/6helloclojure/doc/intro.md b/examples/subsystems/6helloclojure/doc/intro.md deleted file mode 100644 index 61bf8bc1..00000000 --- a/examples/subsystems/6helloclojure/doc/intro.md +++ /dev/null @@ -1,3 +0,0 @@ -# Introduction to hello - -TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) diff --git a/examples/subsystems/6helloclojure/project.clj b/examples/subsystems/6helloclojure/project.clj deleted file mode 100644 index 74434c5f..00000000 --- a/examples/subsystems/6helloclojure/project.clj +++ /dev/null @@ -1,6 +0,0 @@ -(defproject hello "0.1.0-SNAPSHOT" - :description "FIXME: write description" - :url "http://example.com/FIXME" - :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[org.clojure/clojure "1.7.0"]]) diff --git a/examples/subsystems/6helloclojure/src/hello/controllers/main.clj b/examples/subsystems/6helloclojure/src/hello/controllers/main.clj deleted file mode 100644 index d92ebbe1..00000000 --- a/examples/subsystems/6helloclojure/src/hello/controllers/main.clj +++ /dev/null @@ -1,14 +0,0 @@ -(ns hello.controllers.main - (:require [hello.services.greeter :as greet])) - -(defn default [rc] - (assoc rc :greeting (greet/hello (:name rc "anonymous")))) - -(defn do-redirect [rc] - (assoc rc :redirect {:action "main.default" :queryString "name=Mr. Redirect"})) - -(defn stop-it [rc] - (assoc rc :abort :controller :view {:action "main.stopped"})) - -(defn json [rc] - (assoc rc :render {:type :json :data {:a 1 :b "two" :c [3 4 5]}})) diff --git a/examples/subsystems/6helloclojure/src/hello/services/greeter.clj b/examples/subsystems/6helloclojure/src/hello/services/greeter.clj deleted file mode 100644 index 09eed98b..00000000 --- a/examples/subsystems/6helloclojure/src/hello/services/greeter.clj +++ /dev/null @@ -1,3 +0,0 @@ -(ns hello.services.greeter) - -(defn hello [s] (str "Hello " s "!")) diff --git a/examples/subsystems/6helloclojure/test/hello/controllers/main_test.clj b/examples/subsystems/6helloclojure/test/hello/controllers/main_test.clj deleted file mode 100644 index 73d7b9df..00000000 --- a/examples/subsystems/6helloclojure/test/hello/controllers/main_test.clj +++ /dev/null @@ -1,9 +0,0 @@ -(ns hello.controllers.main-test - (:require [clojure.test :refer :all] - [hello.controllers.main :refer :all])) - -(deftest default-item-test - (testing "default name is anonymous" - (is (= "Hello anonymous!" (-> {} default :greeting)))) - (testing "default adds Hello and !" - (is (= "Hello Clojure!" (-> {:name "Clojure"} default :greeting))))) diff --git a/examples/subsystems/6helloclojure/test/hello/services/greeter_test.clj b/examples/subsystems/6helloclojure/test/hello/services/greeter_test.clj deleted file mode 100644 index a53f5ea2..00000000 --- a/examples/subsystems/6helloclojure/test/hello/services/greeter_test.clj +++ /dev/null @@ -1,6 +0,0 @@ -(ns hello.services.greeter-test - (:require [clojure.test :refer :all] - [hello.services.greeter :refer :all])) - -(deftest hello-test - (is (= "Hello Person!" (hello "Person")))) diff --git a/examples/subsystems/6helloclojure/views/main/default.cfm b/examples/subsystems/6helloclojure/views/main/default.cfm deleted file mode 100644 index d1da5a44..00000000 --- a/examples/subsystems/6helloclojure/views/main/default.cfm +++ /dev/null @@ -1,15 +0,0 @@ - - -

Hello!

-

Clojure produced the greeting "#rc.greeting#"

-

We can also get a greeterService in Clojure and use that: - #getBeanFactory().getBean("greeterService").hello("Earthling")#

-

Display this page with a value specified for 'name'.

-

Try calling redirect(). Name will be Mr. Redirect.

-

Try calling abortController(). Also calls setView().

-

Try calling renderData(). You'll get a Clojure structure rendered as JSON!

- -

Sorry!

-

Clojure is not loaded -- most likely due to Leiningen not being installed / found.

-
-
diff --git a/examples/subsystems/6helloclojure/views/main/error.cfm b/examples/subsystems/6helloclojure/views/main/error.cfm deleted file mode 100644 index a758edd9..00000000 --- a/examples/subsystems/6helloclojure/views/main/error.cfm +++ /dev/null @@ -1,19 +0,0 @@ -

An Error Occurred

-

Details of the exception:

- -
    -
  • Failed action: - - - #replace( request.failedAction, chr(60), "<", "all" )# - - unknown - -
  • -
  • Application event: #request.event#
  • -
  • Exception type: #request.exception.type#
  • -
  • Exception message: #request.exception.message#
  • -
  • Exception detail: #request.exception.detail#
  • -
-

Back to the default page?

-
diff --git a/examples/subsystems/6helloclojure/views/main/stopped.cfm b/examples/subsystems/6helloclojure/views/main/stopped.cfm deleted file mode 100644 index 6be5fdc8..00000000 --- a/examples/subsystems/6helloclojure/views/main/stopped.cfm +++ /dev/null @@ -1,5 +0,0 @@ - -

abortController() Called!

-

Check the trace below: after() was not called, and this view is 'main.stopped'.

-

Back to the default page?

-
diff --git a/examples/views/main/default.cfm b/examples/views/main/default.cfm index 66bfe764..9a49e2bf 100644 --- a/examples/views/main/default.cfm +++ b/examples/views/main/default.cfm @@ -10,14 +10,5 @@
  • hello world with layout subsystem
  • hello world controller subsystem
  • hello world service subsystem
  • -
  • - - hello world clojure subsystem - - hello world clojure subsystem not available: clojure is not loaded -- - most likely due to leiningen not being installed / found - -
  • diff --git a/framework/Application.cfc b/framework/Application.cfc index 28b16a26..566286e8 100644 --- a/framework/Application.cfc +++ b/framework/Application.cfc @@ -1,5 +1,5 @@ component { - // Version: FW/1 4.0.0 + // Version: FW/1 4.1.0 // copy this to your application root to use as your Application.cfc // or incorporate the logic below into your existing Application.cfc diff --git a/framework/MyApplication.cfc b/framework/MyApplication.cfc index e4da02a5..67302e1b 100644 --- a/framework/MyApplication.cfc +++ b/framework/MyApplication.cfc @@ -1,5 +1,5 @@ component extends="framework.one" { - // Version: FW/1 4.0.0 + // Version: FW/1 4.1.0 // if you need to provide extension points, copy this to // your web root, next to your Application.cfc, and add diff --git a/framework/WireBoxAdapter.cfc b/framework/WireBoxAdapter.cfc index 02240f58..3b06414a 100644 --- a/framework/WireBoxAdapter.cfc +++ b/framework/WireBoxAdapter.cfc @@ -1,7 +1,7 @@ component extends="wirebox.system.ioc.Injector" { - variables._fw1_version = "4.0.0"; + variables._fw1_version = "4.1.0"; /* - Copyright (c) 2010-2016, Sean Corfield + Copyright (c) 2010-2017, Sean Corfield Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/framework/aop.cfc b/framework/aop.cfc index c80a60ce..c02be2bc 100644 --- a/framework/aop.cfc +++ b/framework/aop.cfc @@ -1,8 +1,8 @@ component extends="framework.ioc" { - variables._fw1_version = "4.0.0"; - variables._aop1_version = "2.0.2"; + variables._fw1_version = "4.1.0"; + variables._aop1_version = "2.0.3"; /* - Copyright (c) 2013-2016, Mark Drew, Sean Corfield, Daniel Budde + Copyright (c) 2013-2017, Mark Drew, Sean Corfield, Daniel Budde Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/framework/beanProxy.cfc b/framework/beanProxy.cfc index c799fd5b..ae13da45 100644 --- a/framework/beanProxy.cfc +++ b/framework/beanProxy.cfc @@ -1,8 +1,8 @@ component { - variables._fw1_version = "4.0.0"; - variables._aop1_version = "2.0.2"; + variables._fw1_version = "4.1.0"; + variables._aop1_version = "2.0.3"; /* - Copyright (c) 2013-2016, Mark Drew, Sean Corfield, Daniel Budde + Copyright (c) 2013-2017, Mark Drew, Sean Corfield, Daniel Budde Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -56,7 +56,7 @@ component { // Prevent infinite loop and make sure the method is publically accessible. if (!structKeyExists(variables.targetBean, arguments.missingMethodName) && !structKeyExists(variables.targetBean, variables.preName & arguments.missingMethodName)) { - objectName = listLast(getMetadata(this).name, "."); + var objectName = listLast(getMetadata(this).name, "."); throw( message="Unable to locate method in (" & objectName & ").", detail="The method (" & arguments.missingMethodName & ") could not be found. Please verify the method exists and is publically accessible."); } @@ -291,11 +291,11 @@ component { { if (arguments.original) { - local.result = evaluate(variables.preName & arguments.methodName & "(argumentCollection = arguments.args)"); + local.result = invoke( variables, variables.preName & arguments.methodName, arguments.args ); } else { - local.result = evaluate(arguments.methodName & "(argumentCollection = arguments.args)"); + local.result = invoke( variables, arguments.methodName, arguments.args ); } if (structKeyExists(local, "result") && !isNull(local.result)) return local.result; @@ -382,7 +382,7 @@ component { private any function $passThrough() { local.methodName = getFunctionCalledName(); - local.result = evaluate("variables.targetBean." & local.methodName & "(argumentCollection = arguments)"); + local.result = invoke( variables.targetBean, local.methodName, arguments ); if (structKeyExists(local, "result") && !isNull(local.result)) return local.result; } diff --git a/framework/cfmljure.cfc b/framework/cfmljure.cfc deleted file mode 100644 index 86c3c780..00000000 --- a/framework/cfmljure.cfc +++ /dev/null @@ -1,406 +0,0 @@ -component { - variables._fw1_version = "4.0.0"; - variables._cfmljure_version = "1.1.0"; -/* - Copyright (c) 2012-2016, Sean Corfield - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - - // constructor - public any function init( string project = "", numeric timeout = 300, - string lein = "lein", // to allow default to be overridden - string boot = "", // to allow Boot to be selected instead - string ns = "", any root = 0 ) { - variables.refCache = { }; - var javaLangSystem = createObject( "java", "java.lang.System" ); - variables.out = javaLangSystem.out; - if ( project != "" ) { - variables._clj_root = this; - variables._clj_ns = ""; - var nl = javaLangSystem.getProperty( "line.separator" ); - var fs = javaLangSystem.getProperty( "file.separator" ); - var nixLike = fs == "/"; - var script = ""; - var cmd = { }; - var tmpDir = ""; - var buildType = ""; - var buildCommand = ""; - if ( len( boot ) ) { - // select Boot build tool - buildType = "boot"; - buildCommand = boot & " aot show -C"; - } else { - buildType = "lein"; - buildCommand = lein & " with-profile production do clean, compile, classpath"; - } - if ( nixLike ) { - // *nix / Mac - tmpDir = "/tmp"; - script = getTempFile( tmpDir, buildType ); - cmd = { - cd = "cd", run = "/bin/sh", arg = script, - // make sure we are not trying to run under root account! - preflightCmd = "if [ `id -u` -eq 0 ]; then >&2 echo 'DO NOT RUN CFML OR CFMLJURE AS ROOT!'; exit 1; fi#nl#", - exitCmd = "exit 0#nl#" - }; - // ensure Servlet container's options do not affect the build tool: - buildCommand = "JAVA_OPTS= " & buildCommand; - } else { - // Windows - tmpDir = replace( javaLangSystem.getenv( "TEMP" ), chr(92), "/", "all" ); - script = getTempFile( tmpDir, buildType ); - script &= ".bat"; - cmd = { - cd = "chdir", run = script, arg = "", - preflightCmd = "", exitCmd = "" - }; - } - variables.__lockFilePath = tmpDir & "/cfmljure.lock"; - fileWrite( - script, - "#cmd.cd# #project#" & nl & - cmd.preflightCmd & - buildCommand & nl & - cmd.exitCmd - ); - var classpath = ""; - var errors = ""; - __acquireLock( variables.__lockFilePath ); - try { - cfexecute( - name="#cmd.run#", arguments="#cmd.arg#", - variable="classpath", errorVariable="errors", - timeout="#timeout#" ); - } catch ( any e ) { - __releaseLock( variables.__lockFilePath ); - if ( structKeyExists( URL, "cfmljure" ) && - URL.cfmljure == "abortOnFailure" ) { - writeDump( var = cmd, label = "Unable to cfexecute this script" ); - if ( !isNull( classpath ) ) writeDump( var = classpath, label = "Build (#buildType#) stdout" ); - if ( !isNull( errors ) ) writeDump( var = errors, label = "Build (#buildType#) stderr" ); - writeDump( var = e, label = "Full stack trace" ); - abort; - } - throw e; - } - __releaseLock( variables.__lockFilePath ); - try { - fileDelete( script ); - } catch ( any e ) { - variables.out.println( "Unable to delete #script#!!!" ); - } - // could be multiple lines so clean it up: - classpath = listLast( classpath, nl ); - classpath = replace( classpath, nl, "" ); - // turn the classpath into a URL list: - var classpathParts = listToArray( classpath, javaLangSystem.getProperty( "path.separator" ) ); - var urls = [ ]; - var cfmlInteropAvailable = false; - for ( var part in classpathParts ) { - if ( !fileExists( part ) && !directoryExists( part ) ) { - try { - directoryCreate( part ); - } catch ( any e ) { - // ignore and hope for the best - really! - } - } - if ( !part.endsWith( ".jar" ) && !part.endsWith( fs ) ) { - part &= fs; - } - if ( REFind( "cfml-interop-[-.0-9a-zA-Z_]+\.jar", part ) ) { - cfmlInteropAvailable = true; - } - // TODO: shortcut this... - var file = createObject( "java", "java.io.File" ).init( part ); - arrayAppend( urls, file.toURI().toURL() ); - } - // extend the classloader - not at all sketchy, honest! - var threadProxy = createObject( "java", "java.lang.Thread" ); - var appCL = threadProxy.currentThread().getContextClassLoader(); - var urlCLProxy = createObject( "java", "java.net.URLClassLoader" ); - var addURL = urlCLProxy.getClass().getDeclaredMethod( "addURL", __classes( "URL", 1, "java.net" ) ); - addUrl.setAccessible( true ); // hack to make it callable - for ( var newURL in urls.toArray() ) { - addURL.invoke( appCL, [ newURL ] ); - } - try { - var clj6 = appCL.loadClass( "clojure.java.api.Clojure" ); - variables.out.println( "Detected Clojure 1.6 or later" ); - this._clj_var = clj6.getMethod( "var", __classes( "Object", 2 ) ); - this._clj_read = clj6.getMethod( "read", __classes( "String" ) ); - } catch ( any e ) { - try { - var clj5 = appCL.loadClass( "clojure.lang.RT" ); - variables.out.println( "Falling back to Clojure 1.5 or earlier" ); - this._clj_var = clj5.getMethod( "var", __classes( "String", 2 ) ); - this._clj_read = clj5.getMethod( "readString", __classes( "String" ) ); - } catch ( any e ) { - variables.out.println( "Unable to load any version of Clojure" ); - variables.out.println( "Aborting install of Clojure integration!" ); - // promote the only part of the API that will work - this.isAvailable = this.__isAvailable; - return this; - } - } - // promote API: - this.install = this.__install; - this.isAvailable = this.__isAvailable; - this.read = this.__read; - var autoLoaded = "clojure.core,clojure.walk"; - if ( cfmlInteropAvailable ) { - variables.out.println( "Detected cfml-interop for interop" ); - // perform the best interop we can: - autoLoaded = listAppend( autoLoaded, "cfml.interop" ); - this.toCFML = this.__toCljStruct; - this.toClojure = this.__toCljStruct; - } else { - variables.out.println( "Falling back to clojure.walk for interop" ); - // fall back to basic interop: - this.toCFML = this.__toCFML; - this.toClojure = this.__toClojure; - } - __install( autoLoaded, this ); - } else if ( ns != "" ) { - variables._clj_root = root; - variables._clj_ns = ns; - } else { - throw "cfmljure requires the path of a Clojure project."; - } - return this; - } - - public any function _( string name ) { - return __( name, true ); - } - - private void function __acquireLock( string lockFilePath ) { - var waits = 0; - while ( fileExists( lockFilePath ) ) { - if ( waits > 3 ) throw "cfmljure waited a long time for #lockFilePath# to be deleted - perhaps you should delete it manually and try again?"; - variables.out.println( "Waiting for #lockFilePath# to be deleted..." ); - sleep( ( 15 * randRange( 1, 15 ) ) * 1000 ); - ++waits; - } - fileWrite( lockFilePath, "" ); - } - - private void function __releaseLock( string lockFilePath ) { - try { - fileDelete( lockFilePath ); - } catch ( any e ) { - variables.out.println( "Unable to delete #lockFilePath#!!!" ); - } - } - - public any function __install( any nsList, struct target ) { - if ( !isArray( nsList ) ) nsList = listToArray( nsList ); - try { - __acquireLock( variables.__lockFilePath ); - for ( var ns in nsList ) { - __1_install( trim( ns ), target ); - } - } finally { - __releaseLock( variables.__lockFilePath ); - } - } - - public boolean function __isAvailable() { - return structKeyExists( this, "_clj_var" ) || - structKeyExists( variables, "_clj_root" ) && - structKeyExists( variables._clj_root, "_clj_var" ); - } - - public any function __read( string expr ) { - var args = [ expr ]; - return variables._clj_root._clj_read.invoke( javaCast( "null", 0 ), args.toArray() ); - } - - public any function __toCFML( any expr ) { - return this.clojure.walk.stringify_keys( - isNull( expr ) ? javaCast( "null", 0 ) : expr - ); - } - - public any function __toCljStruct( any expr ) { - return this.cfml.interop.to_clj_struct( - isNull( expr ) ? javaCast( "null", 0 ) : expr - ); - } - - public any function __toClojure( any expr ) { - return this.clojure.walk.keywordize_keys( - isNull( expr ) ? javaCast( "null", 0 ) : - ( isStruct( expr ) ? - this.clojure.core.into( this.clojure.core.hash_map(), expr ) : - expr ) - ); - } - - // helper functions: - - public any function __( string name, boolean autoDeref ) { - if ( !structKeyExists( variables.refCache, name ) ) { - if ( autoDeref ) { - variables.refCache[ name ] = variables._clj_root.clojure.core.deref( __var( variables._clj_ns, name ) ); - } else { - variables.refCache[ name ] = __var( variables._clj_ns, name ); - } - } - return variables.refCache[ name ]; - } - - public any function __classes( string name, numeric n = 1, string prefix = "java.lang" ) { - var result = createObject( "java", "java.util.ArrayList" ).init(); - var type = createObject( "java", prefix & "." & name ).getClass(); - while ( n-- > 0 ) result.add( type ); - var classType = createObject( "java", "java.lang.Class" ); - var arrayType = createObject( "java", "java.lang.reflect.Array" ); - var arrayInstance = arrayType.newInstance( classType.getClass(), result.size() ); - return result.toArray( arrayInstance ); - } - - public any function __1_install( string ns, struct target ) { - __require( ns ); - __2_install( listToArray( ns, "." ), target ); - } - - public any function __2_install( array nsParts, struct target ) { - var first = replace( nsParts[ 1 ], "-", "_", "all" ); - var ns = replace( nsParts[ 1 ], "_", "-", "all" ); - var n = arrayLen( nsParts ); - if ( !structKeyExists( target, first ) ) { - target[ first ] = new cfmljure( - ns = listAppend( variables._clj_ns, ns, "." ), - root = variables._clj_root - ); - } - if ( n > 1 ) { - arrayDeleteAt( nsParts, 1 ); - target[ first ].__2_install( nsParts, target[ first ] ); - } - } - - public any function __call( any v, any argsArray ) { - switch ( arrayLen( argsArray ) ) { - case 0: - return v.invoke(); - break; - case 1: - return v.invoke( argsArray[1] ); - break; - case 2: - return v.invoke( argsArray[1], argsArray[2] ); - break; - case 3: - return v.invoke( argsArray[1], argsArray[2], argsArray[3] ); - break; - case 4: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4] ); - break; - case 5: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5] ); - break; - case 6: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5], argsArray[6] ); - break; - case 7: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5], argsArray[6], - argsArray[7] ); - break; - case 8: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5], argsArray[6], - argsArray[7], argsArray[8] ); - break; - case 9: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5], argsArray[6], - argsArray[7], argsArray[8], argsArray[9] ); - break; - case 10: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5], argsArray[6], - argsArray[7], argsArray[8], argsArray[9], - argsArray[10] ); - break; - case 11: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5], argsArray[6], - argsArray[7], argsArray[8], argsArray[9], - argsArray[10], argsArray[11] ); - break; - case 12: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], - argsArray[4], argsArray[5], argsArray[6], - argsArray[7], argsArray[8], argsArray[9], - argsArray[10], argsArray[11], argsArray[12] ); - break; - case 13: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], argsArray[4], argsArray[5], - argsArray[6], argsArray[7], argsArray[8], argsArray[9], argsArray[10], - argsArray[11], argsArray[12], argsArray[13] ); - case 14: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], argsArray[4], argsArray[5], - argsArray[6], argsArray[7], argsArray[8], argsArray[9], argsArray[10], - argsArray[11], argsArray[12], argsArray[13], argsArray[14] ); - case 15: - return v.invoke( argsArray[1], argsArray[2], argsArray[3], argsArray[4], argsArray[5], - argsArray[6], argsArray[7], argsArray[8], argsArray[9], argsArray[10], - argsArray[11], argsArray[12], argsArray[13], argsArray[14], argsArray[15] ); - default: - throw "cfmljure cannot call that method with that many arguments."; - break; - } - } - - public string function __name() { - return variables._clj_ns; - } - - public void function __require( string ns ) { - if ( !structKeyExists( variables, "_clj_require" ) ) { - variables._clj_require = __var( "clojure.core", "require" ); - } - variables._clj_require.invoke( this.read( ns ) ); - } - - public any function __var( string ns, string name ) { - var encodes = [ "_qmark_", "_bang_", "_gt_", "_lt_", "_eq_", "_star_", "_" ]; - var decodes = [ "?", "!", ">", "<", "=", "*", "-" ]; - var n = encodes.len(); - for ( var i = 1; i <= n; ++i ) { - name = replaceNoCase( name, encodes[i], decodes[i], "all" ); - } - var args = [ lCase( ns ), lCase( name ) ]; - return variables._clj_root._clj_var.invoke( javaCast( "null", 0 ), args.toArray() ); - } - - public any function onMissingMethod( string missingMethodName, any missingMethodArguments ) { - if ( left( missingMethodName, 1 ) == "_" ) { - return __( right( missingMethodName, len( missingMethodName ) - 1 ), true ); - } else { - var clj_var = __( missingMethodName, false ); - if ( isNull( clj_var ) ) { - throw "Unable to resolve #variables._clj_ns#/#missingMethodName#"; - } - return __call( clj_var, missingMethodArguments ); - } - } - -} diff --git a/framework/cljcontroller.cfc b/framework/cljcontroller.cfc deleted file mode 100644 index 18c41853..00000000 --- a/framework/cljcontroller.cfc +++ /dev/null @@ -1,103 +0,0 @@ -component { - variables._fw1_version = "4.0.0"; - variables._ioclj_version = "1.0.1"; - /* - Copyright (c) 2015-2016, Sean Corfield - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - function init( any fw, any cfmljure, any ns ) { - variables.fw = fw; - variables.cfmljure = cfmljure; - variables.ns = ns; - return this; - } - - function onMissingMethod( string missingMethodName, struct missingMethodArguments ) { - if ( structKeyExists( missingMethodArguments, "rc" ) ) { - var rc = missingMethodArguments.rc; - try { - var rcClj = variables.cfmljure.toClojure( rc ); - var rawResult = callClojure( missingMethodName, rcClj ); - var result = variables.cfmljure.toCFML( rawResult ); - structClear( rc ); - structAppend( rc, result ); - // post-process special keys in rc for abort / redirect etc - var core = variables.cfmljure.clojure.core; - if ( structKeyExists( rc, "redirect" ) && isStruct( rc.redirect ) && - structKeyExists( rc.redirect, "action" ) ) { - if ( isObject( variables.fw ) ) { - variables.fw.redirect( - action = rc.redirect["action"], - preserve = structKeyExists( rc.redirect, "preserve" ) ? rc.redirect["preserve"] : "none", - append = structKeyExists( rc.redirect, "append" ) ? rc.redirect["append"] : "none", - queryString = structKeyExists( rc.redirect, "queryString" ) ? rc.redirect["queryString"] : "", - statusCode = structKeyExists( rc.redirect, "statusCode" ) ? rc.redirect["statusCode"] : "302" - ); - } else { - throw "Unable to redirect() due to lack of injected FW/1"; - } - } - if ( structKeyExists( rc, "render" ) && isStruct( rc.render ) && - structKeyExists( rc.render, "type" ) && structKeyExists( rc.render, "data" ) ) { - if ( isObject( variables.fw ) ) { - var walk = variables.cfmljure.clojure.walk; - var renderer = variables.fw.renderData( - core.name( rc.render["type"] ), - // since Clojure generated the render data we must be careful to - // preserve case but still convert keys to strings... - walk.stringify_keys( core.get( core.get( rawResult, core.keyword( "render" ) ), core.keyword( "data" ) ) ) - ); - if ( structKeyExists( rc.render, "statusCode" ) ) renderer.statusCode( rc.render["statusCode"] ); - if ( structKeyExists( rc.render, "statusText" ) ) renderer.statusText( rc.render["statusText"] ); - } else { - throw "Unable to renderData() due to lack of injected FW/1"; - } - } - if ( structKeyExists( rc, "view" ) && isStruct( rc.view ) && - structKeyExists( rc.view, "action" ) ) { - if ( isObject( variables.fw ) ) { - variables.fw.setView( rc.view["action"] ); - } else { - throw "Unable to setView() due to lack of injected FW/1"; - } - } - if ( structKeyExists( rc, "abort" ) && core.keyword_qmark_( rc.abort ) && - core.name( rc.abort ) == "controller" ) { - if ( isObject( variables.fw ) ) { - variables.fw.abortController(); - } else { - throw "Unable to abortController() due to lack of injected FW/1"; - } - } - } catch ( java.lang.IllegalStateException e ) { - if ( e.message.startsWith( "Attempting to call unbound fn" ) ) { - // no such controller method - ignore it - this[ missingMethodName ] = __dummy; - } else { - throw e; - } - } - } - } - - function setFramework() { } - - function __dummy() { } - - function callClojure( string qualifiedName, any rcClj ) { - return evaluate( "variables.ns.#qualifiedName#( rcClj )" ); - } - -} diff --git a/framework/facade.cfc b/framework/facade.cfc index 50026271..3b8fb932 100644 --- a/framework/facade.cfc +++ b/framework/facade.cfc @@ -1,7 +1,7 @@ component { - variables._fw1_version = "4.0.0"; + variables._fw1_version = "4.1.0"; /* - Copyright (c) 2016, Sean Corfield + Copyright (c) 2016-2017, Sean Corfield Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/framework/ioc.cfc b/framework/ioc.cfc index b02016c2..e25d3cf6 100644 --- a/framework/ioc.cfc +++ b/framework/ioc.cfc @@ -1,8 +1,8 @@ component { - variables._fw1_version = "4.0.0"; - variables._di1_version = "1.2.0"; + variables._fw1_version = "4.1.0"; + variables._di1_version = "1.3.0"; /* - Copyright (c) 2010-2016, Sean Corfield + Copyright (c) 2010-2017, Sean Corfield Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -49,18 +49,13 @@ component { variables.settersInfo = { }; variables.autoExclude = [ '/WEB-INF', '/Application.cfc', // never manage these! - '/Application.lc', '/Application.lucee', // assume default name for intermediary: '/MyApplication.cfc', - '/MyApplication.lc', '/MyApplication.lucee', 'framework.cfc', 'ioc.cfc', // legacy FW/1 / DI/1 // recent FW/1 + DI/1 + AOP/1 exclusions: '/framework/aop.cfc', '/framework/beanProxy.cfc', '/framework/ioc.cfc', '/framework/WireBoxAdapter.cfc', - '/framework/one.cfc', - // and Clojure-related exclusions: - '/framework/cfmljure.cfc', '/framework/cljcontroller.cfc', - '/framework/ioclj.cfc' + '/framework/one.cfc' ]; variables.listeners = 0; setupFrameworkDefaults(); @@ -178,8 +173,6 @@ component { var basePath = replace( dottedPath, '.', '/', 'all' ); var cfcPath = expandPath( '/' & basePath & '.cfc' ); var expPath = cfcPath; - if ( !fileExists( expPath ) ) expPath = expandPath( '/' & basePath & '.lc' ); - if ( !fileExists( expPath ) ) expPath = expandPath( '/' & basePath & '.lucee' ); if ( !fileExists( expPath ) ) throw "Unable to find source file for #dottedPath#: expands to #cfcPath#"; var cfcPath = replace( expPath, chr(92), '/', 'all' ); var metadata = { @@ -309,7 +302,7 @@ component { if ( !isNull( properties[ property ] ) ) { var args = { }; args[ property ] = properties[ property ]; - evaluate( 'bean.set#property#( argumentCollection = args )' ); + invoke( bean, "set#property#", args ); } } return bean; @@ -519,10 +512,13 @@ component { lock name="#application.applicationName#_ioc1_#variables.folderList#" type="exclusive" timeout="30" { if ( structKeyExists( variables, 'discoveryComplete' ) ) return; variables.pathMapCache = { }; - for ( var f in variables.folderArray ) { - discoverBeansInFolder( replace( f, chr(92), '/', 'all' ) ); + try { + for ( var f in variables.folderArray ) { + discoverBeansInFolder( replace( f, chr(92), '/', 'all' ) ); + } + } finally { + variables.discoveryComplete = true; } - variables.discoveryComplete = true; } onLoadEvent(); } @@ -534,10 +530,6 @@ component { var cfcs = [ ]; try { cfcs = directoryList( folder, variables.config.recurse, 'path', '*.cfc' ); - var lcs = directoryList( folder, variables.config.recurse, 'path', '*.lc' ); - for ( var l in lcs ) arrayAppend( cfcs, l ); - lcs = directoryList( folder, variables.config.recurse, 'path', '*.lucee' ); - for ( l in lcs ) arrayAppend( cfcs, l ); } catch ( any e ) { // assume bad path - ignore it, cfcs is empty list } @@ -724,10 +716,16 @@ component { // do enough resolution to create and initialization this bean // returns a struct of the bean and a struct of beans and setters still to run // construction phase: - if ( !structKeyExists( variables.accumulatorCache, beanName ) ) { + var accumulator = { injection = { } }; + // ensure only injection singletons end up cached in variables scope + if ( structKeyExists( variables.accumulatorCache, beanName ) ) { + structAppend( accumulator.injection, variables.accumulatorCache[ beanName ].injection ); + } else { variables.accumulatorCache[ beanName ] = { injection = { }, dependencies = { } }; } - var partialBean = resolveBeanCreate( beanName, variables.accumulatorCache[ beanName ], constructorArgs ); + // all dependencies can be cached in variables scope + accumulator.dependencies = variables.accumulatorCache[ beanName ].dependencies; + var partialBean = resolveBeanCreate( beanName, accumulator, constructorArgs ); if ( structKeyExists( variables.resolutionCache, beanName ) && variables.resolutionCache[ beanName ] ) { // fully resolved, no action needed this time @@ -738,6 +736,10 @@ component { // injection phase: // now perform all of the injection: for ( var name in partialBean.injection ) { + if ( structKeyExists( variables.accumulatorCache[ beanName ].injection, name ) ) { + // this singleton is in the accumulatorCache, thus it has already been fully resolved + continue; + } var injection = partialBean.injection[ name ]; if ( checkForPostInjection && !isConstant( name ) && structKeyExists( injection.bean, initMethod ) ) { postInjectables[ name ] = true; @@ -760,7 +762,7 @@ component { // isNull() does not always work on ACF10... try { if ( isNull( args[ property ] ) ) continue; } catch ( any e ) { continue; } } - evaluate( 'injection.bean.set#property#( argumentCollection = args )' ); + invoke( injection.bean, "set#property#", args ); } } // post-injection, pre-init-method phase: @@ -772,6 +774,11 @@ component { for ( var postName in postInjectables ) { callInitMethod( postName, postInjectables, partialBean, initMethod ); } + for ( name in partialBean.injection ) { + if ( isSingleton( name ) ) { + variables.accumulatorCache[ beanName ].injection[ name ] = partialBean.injection[ name ]; + } + } variables.resolutionCache[ beanName ] = isSingleton( beanName ); } return partialBean.bean; @@ -796,7 +803,7 @@ component { } else { variables.initMethodCache[ name ] = isSingleton( name ); var bean = info.injection[ name ].bean; - evaluate( 'bean.#method#()' ); + invoke( bean, method ); } } } @@ -859,7 +866,7 @@ component { } } } - var __ioc_newBean = evaluate( 'bean.init( argumentCollection = args )' ); + var __ioc_newBean = bean.init( argumentCollection = args ); // if the constructor returns anything, it becomes the bean // this allows for smart constructors that return things other // than the CFC being created, such as implicit factory beans @@ -890,9 +897,6 @@ component { } } } - if ( !isSingleton( beanName ) && structKeyExists( accumulator.injection, beanName ) ) { - accumulator.injection[ beanName ].bean = bean; - } } else if ( isConstant( beanName ) ) { bean = info.value; accumulator.injection[ beanName ] = { bean = info.value, setters = { } }; @@ -911,7 +915,7 @@ component { if ( isCustomFunction( fmBean ) || isClosure( fmBean ) ) { bean = fmBean( argumentCollection = argStruct ); } else { - bean = evaluate( 'fmBean.#info.method#( argumentCollection = argStruct )' ); + bean = invoke( fmBean, "#info.method#", argStruct ); } accumulator.injection[ beanName ] = { bean = bean, setters = { } }; } else { diff --git a/framework/ioclj.cfc b/framework/ioclj.cfc deleted file mode 100644 index ebc5af8f..00000000 --- a/framework/ioclj.cfc +++ /dev/null @@ -1,246 +0,0 @@ -component extends=framework.ioc { - variables._fw1_version = "4.0.0"; - variables._ioclj_version = "1.1.0"; -/* - Copyright (c) 2015-2016, Sean Corfield - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - - // CONSTRUCTOR - - public any function init( any folders, struct config = { } ) { - variables.debug = structKeyExists( config, "debug" ) ? config.debug : false; - if ( variables.debug ) { - variables.stdout = createObject( "java", "java.lang.System" ).out; - } - if ( isSimpleValue( folders ) ) { - folders = listToArray( folders ); - } - var cfmlFolders = [ ]; - var cljFolders = [ ]; - for ( var folder in folders ) { - if ( len( folder ) > 4 && left( folder, 4 ) == "clj:" ) { - arrayAppend( cljFolders, right( folder, len( folder ) - 4 ) ); - } else if ( len( folder ) > 5 && left( folder, 5 ) == "cfml:" ) { - arrayAppend( cfmlFolders, right( folder, len( folder ) - 5 ) ); - } else { - arrayAppend( cfmlFolders, folder ); - arrayAppend( cljFolders, folder ); - } - } - variables.cljFolderArray = cljFolders; - // initialize DI/1 parent - super.init( cfmlFolders, config ); - variables.cljBeans = { }; - if ( structKeyExists( config, "noClojure" ) && config.noClojure ) return; - var lein = structKeyExists( config, "lein" ) ? config.lein : "lein"; - var boot = structKeyExists( config, "boot" ) ? config.boot : ""; // default is not Boot - var cljcontroller = structKeyExists( config, "cljcontroller" ) ? config.cljcontroller : "framework.cljcontroller"; - // find the first folder that includes project.clj (or build.boot) - that's our project - variables.project = findProjectFile( len( boot ) ? "build.boot" : "project.clj" ); - discoverClojureFiles(); - // list of namespaces to expose: - var ns = [ ]; - for ( var beanName in variables.cljBeans ) { - arrayAppend( ns, replace( variables.cljBeans[ beanName ].ns, "-", "_", "all" ) ); - } - // and create a cfmljure instance - var timeout = structKeyExists( config, "timeout" ) ? config.timeout : 300; - var useServerScope = structKeyExists( config, "server" ) ? config.server : false; - var cfmljure = 0; - if ( useServerScope ) { - if ( !structKeyExists( server, "__cfmljure" ) ) { - server.__cfmljure = new framework.cfmljure( variables.project, timeout, lein, boot ); - } - cfmljure = server.__cfmljure; - } else { - cfmljure = new framework.cfmljure( variables.project, timeout, lein, boot ); - } - if ( cfmljure.isAvailable() ) { - // Clojure loaded -- install the discovered namespaces - var app = { }; - cfmljure.install( ns, app ); - variables.clojureApp = app; - } else { - // Clojure failed to load -- forget any installed beans - variables.cljBeans = { }; - } - variables.cfmljure = cfmljure; - this.onLoad( function( bf ) { - // patch DI/1 bean info to include Clojure "beans" -- this allows Clojure - // to be autowired like any other "value" bean: - for ( var cljBean in variables.cljBeans ) { - var info = variables.cljBeans[ cljBean ]; - // navigate to actual namespace "object": - var ns = variables.clojureApp; - for ( var x in info.nsx ) { - ns = ns[ x ]; - } - var bean = ns; - if ( info.type == "controller" ) { - // need a wrapper - try to find FW/1 instance via bean factory: - var fw = containsBean( "fw" ) ? getBean( "fw" ) : - ( containsBean( "fw1" ) ? getBean( "fw1" ) : - ( containsBean( "framework" ) ? getBean( "framework" ) : - "" ) ); - var controller = new "#cljcontroller#"( - fw, variables.cfmljure, ns - ); - bean = controller; - } - variables.beanInfo[ cljBean ] = { - name : cljBean, value : bean, isSingleton : true - }; - } - // add cfmljure to expose Clojure-related functions: - bf.addBean( "cfmljure", cfmljure ); - } ); - return this; - } - - // PUBLIC METHODS - - // convenience API for metaprogramming perhaps? - public any function getBeanInfo( string beanName = '', boolean flatten = false, - string regex = '' ) { - if ( len( beanName ) ) { - // ask about a specific bean: - if ( structKeyExists( variables.cljBeans, beanName ) ) { - return variables.cljBeans[ beanName ]; - } - return super.getBeanInfo( beanName, flatten, regex ); - } else { - var result = { beanInfo = { } }; - var superInfo = super.getBeanInfo( beanName, flatten, regex ); - structAppend( result.beanInfo, variables.cljBeans ); - structAppend( result.beanInfo, superInfo.beanInfo ); - if ( structKeyExists( superInfo, 'parent' ) ) { - result.parent = superInfo.parent; - } - if ( len( regex ) ) { - var matched = { }; - for ( var name in result.beanInfo ) { - if ( REFind( regex, name ) ) { - matched[ name ] = result.beanInfo[ name ]; - } - } - result.beanInfo = matched; - } - return result; - } - } - - - // reload-all a given namespace or reload all - public void function reload( string ns ) { - if ( !variables.cfmljure.isAvailable() ) return; - var core = variables.cfmljure.clojure.core; - if ( ns == "all" ) { - for ( var beanName in variables.cljBeans ) { - var info = variables.cljBeans[ beanName ]; - core.require( core.symbol( info.ns ), core.keyword( "reload" ) ); - } - } else { - core.require( core.symbol( ns ), core.keyword( "reload-all" ) ); - } - } - - // PRIVATE HELPERS - - private void function discoverClojureFiles() { - var cljs = [ ]; - for ( var folder in variables.cljFolderArray ) { - var src = folder & "/src"; - var expandedFolder = expandPath( src ); - if ( directoryExists( expandedFolder ) ) src = expandedFolder; - if ( !directoryExists( src ) ) continue; - var n = len( src ) + 1; // allow for trailing / - try { - cljs = directoryList( src, true, "path", "*.clj" ); - // we also support .cljc files - var cljcs = directoryList( src, true, "path", "*.cljc" ); - for ( var cljcOSPath in cljcs ) cljs.append( cljcOSPath ); - } catch ( any e ) { - // assume bad path and ignore it - } - for ( var cljOSPath in cljs ) { - var cljPath = replace( cljOSPath, chr(92), "/", "all" ); - cljPath = right( cljPath, len( cljPath ) - n ); - // allow for extension being either .clj or .cljc - cljPath = left( cljPath, len( cljPath ) - ( right( cljPath, 1 ) == "c" ? 5 : 4 ) ); - var ns = replace( replace( cljPath, "/", ".", "all" ), "_", "-", "all" ); - // per #366, the pattern allowed is - // top-level(.optional)*.plural.(prefix.)*name - // and this will generate prefixNameSingular - var parts = listToArray( cljPath, "/" ); - var nParts = arrayLen( parts ); - // ignore temp files from editors (starting with .) - if ( left( parts[ nParts ], 1 ) == "." ) continue; - if ( nParts >= 3 ) { - var pluralCandidate = 2; - do { - var lbo = parts[ pluralCandidate ]; - var lbo1 = singular( lbo ); - ++pluralCandidate; - } while ( lbo == lbo1 && pluralCandidate < nParts ); - if ( lbo1 != lbo ) { - var beanName = ""; - while ( pluralCandidate <= nParts ) { - beanName &= parts[ pluralCandidate ]; - ++pluralCandidate; - } - beanName &= lbo1; - if ( structKeyExists( variables.cljBeans, beanName ) ) { - throw "#beanName# is not unique (from #cljPath#)"; - } else { - variables.cljBeans[ beanName ] = { - ns : ns, nsx : parts, type : lbo1, - isSingleton : true // for DI/1 compatibility - }; - } - } else if ( variables.debug ) { - variables.stdout.println( "ioclj: ignoring #cljPath#.clj because it has no plural segment" ); - } - } else if ( variables.debug ) { - variables.stdout.println( "ioclj: ignoring #cljPath#.clj because it does not have at least three segments" ); - } - } - } - } - - private string function findProjectFile( string buildFile ) { - for ( var folder in variables.cljFolderArray ) { - if ( right( folder, 1 ) == "/" ) { - if ( len( folder ) == 1 ) folder = ""; - else folder = left( folder, len( folder ) - 1 ); - } - var expandedFolder = expandPath( folder ); - // for ACF11 compatibility, only use expanded path if it exists - if ( directoryExists( expandedFolder ) ) folder = expandedFolder; - if ( !directoryExists( folder ) ) continue; - var path = replace( folder, chr(92), "/", "all" ); - if ( right( path, 1 ) == "/" ) { - if ( len( path ) == 1 ) path = ""; - else path = left( path, len( path ) - 1 ); - } - if ( fileExists( path & "/" & buildFile ) ) { - // found our Clojure project, return it - if ( variables.debug ) variables.stdout.println( "ioclj: using #path#/#buildFile# for Clojure root" ); - return path; - } - } - throw "Unable to find #buildFile# in any of: #arrayToList( variables.cljFolderArray )#"; - } - -} diff --git a/framework/methodProxy.cfc b/framework/methodProxy.cfc new file mode 100644 index 00000000..2cd50e14 --- /dev/null +++ b/framework/methodProxy.cfc @@ -0,0 +1,30 @@ +component { + variables._fw1_version = "4.1.0"; + /* + Copyright (c) 2017, Sean Corfield + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + function init( fw, method ) { + variables.fw = fw; + variables.method = method; + return this; + } + + // implements Java 8 Function interface + function apply( arg ) { + return invoke( variables.fw, method, [ arg ] ); + } + +} diff --git a/framework/one.cfc b/framework/one.cfc index 0b7901b4..222fdd27 100644 --- a/framework/one.cfc +++ b/framework/one.cfc @@ -1,7 +1,7 @@ component { - variables._fw1_version = "4.0.0"; + variables._fw1_version = "4.1.0"; /* - Copyright (c) 2009-2016, Sean Corfield, Marcin Szczepanski, Ryan Cogswell + Copyright (c) 2009-2017, Sean Corfield, Marcin Szczepanski, Ryan Cogswell Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -267,6 +267,14 @@ component { } } + /* + * can be overridden to customize how views and layouts are actually + * rendered; should return null if the default rendering should apply + */ + public any function customTemplateEngine( string type, string path, struct scope ) { + return; + } + /* * can be overridden to customize how views and layouts are found - can be * used to provide skinning / common views / layouts etc @@ -307,10 +315,9 @@ component { public void function frameworkTrace( string message ) { if ( request._fw1.doTrace ) { try { - if ( isDefined( 'session._fw1_trace' ) && - structKeyExists( session, '_fw1_trace' ) ) { - request._fw1.trace = session._fw1_trace; - structDelete( session, '_fw1_trace' ); + if ( sessionHas( '_fw1_trace' ) ) { + request._fw1.trace = sessionRead( '_fw1_trace' ); + sessionDelete( '_fw1_trace' ); } } catch ( any _ ) { // ignore if session is not enabled @@ -692,6 +699,22 @@ component { return internalLayout( layoutPath, body ); } + /* + * Exotic utility function to create proxies for FW/1 methods that can be + * called from Java: can be used with external rendering engines, for example + * NOTE: requires Java 8 for Function<> interface! + */ + public struct function makeMethodProxies( array methodNames ) { + var proxies = { }; + for ( var method in methodNames ) { + proxies[ method ] = createDynamicProxy( + new framework.methodProxy( this, method ), + [ "java.util.function.Function" ] + ); + } + return proxies; + } + /* * it is better to set up your application configuration in * your setupApplication() method since that is called on a @@ -729,6 +752,7 @@ component { // reset lifecycle flags: structDelete( request, 'layout' ); structDelete( request._fw1, 'controllerExecutionStarted' ); + structDelete( request._fw1, 'overrideLayoutAction' ); structDelete( request._fw1, 'overrideViewAction' ); if ( structKeyExists( request._fw1, 'renderData' ) ) { // need to reset the content type as well! @@ -741,14 +765,24 @@ component { } // setup the new controller action, based on the error action: request._fw1.controllers = [ ]; - - if ( structKeyExists( variables, 'framework' ) && structKeyExists( variables.framework, 'error' ) ) { - request.action = variables.framework.error; + var key = 'error'; + var defaultAction = 'main.error'; + try { + if ( exception.type == 'fw1.viewnotfound' && structKeyExists( variables.framework, 'missingview' ) ) { + key = 'missingview'; + // shouldn't be needed -- key will be present in framework config + defaultAction = 'main.missingview'; + } + } catch ( any e ) { + // leave it as exception + } + if ( structKeyExists( variables, 'framework' ) && structKeyExists( variables.framework, key ) ) { + request.action = variables.framework[ key ]; } else { // this is an edge case so we don't bother with subsystems etc // (because if part of the framework defaults are not present, // we'd have to do a lot of conditional logic here!) - request.action = 'main.error'; + request.action = defaultAction; } // ensure request.context is available if ( !structKeyExists( request, 'context' ) ) { @@ -789,7 +823,7 @@ component { viewNotFound(); // if we got here, we would return the string or struct to be rendered // but viewNotFound() throws an exception... - // for example, return view( 'main.missing' ); + // for example, return view( 'main/missing' ); } /* @@ -804,6 +838,17 @@ component { public void function onPopulateError( any cfc, string property, struct rc ) { } + /* + * This can be overridden if you want to take some actions when the + * framework is about to be reloaded, prior to starting the next + * application cycle. This will be called when an explicit reload is + * performed, or on each request if reloadApplicationOnEveryRequest is + * set true. You could use it to perform housekeeping of services, prior + * to them all being recreated in a new bean factory, for example. + */ + public void function onReload() { + } + /* * not intended to be overridden, automatically deleted for CFC requests */ @@ -918,7 +963,10 @@ component { public any function onRequestStart( string targetPath ) { setupRequestDefaults(); - if ( !isFrameworkInitialized() || isFrameworkReloadRequest() ) { + if ( !isFrameworkInitialized() ) { + setupApplicationWrapper(); + } else if ( isFrameworkReloadRequest() ) { + onReload(); setupApplicationWrapper(); } else { request._fw1.theApp = getFw1App(); @@ -964,7 +1012,6 @@ component { var args = { }; args[ property ] = props[ property ]; if ( trim && isSimpleValue( args[ property ] ) ) args[ property ] = trim( args[ property ] ); - // cfc[ 'set'&property ]( argumentCollection = args ); // ugh! no portable script version of this?!?! setProperty( cfc, property, args ); } catch ( any e ) { onPopulateError( cfc, property, props ); @@ -977,7 +1024,6 @@ component { var args = { }; args[ property ] = props[ property ]; if ( trim && isSimpleValue( args[ property ] ) ) args[ property ] = trim( args[ property ] ); - // cfc[ 'set'&property ]( argumentCollection = args ); // ugh! no portable script version of this?!?! setProperty( cfc, property, args ); } else if ( deep && structKeyExists( cfc, 'get' & property ) ) { // look for a property that starts with the property @@ -1003,7 +1049,6 @@ component { var args = { }; args[ trimProperty ] = props[ trimProperty ]; if ( trim && isSimpleValue( args[ trimProperty ] ) ) args[ trimProperty ] = trim( args[ trimProperty ] ); - // cfc[ 'set'&trimproperty ]( argumentCollection = args ); // ugh! no portable script version of this?!?! setProperty( cfc, trimProperty, args ); } } else if ( deep ) { @@ -1037,7 +1082,7 @@ component { // call from your controller to redirect to a clean URL based on an action, pushing data to flash scope if necessary: public void function redirect( string action, string preserve = 'none', string append = 'none', string path = variables.magicBaseURL, - string queryString = '', string statusCode = '302', string header = '' + any queryString = '', string statusCode = '302', string header = '' ) { if ( path == variables.magicBaseURL ) path = getBaseURL(); var preserveKey = ''; @@ -1093,7 +1138,7 @@ component { if ( request._fw1.doTrace ) { internalFrameworkTrace( 'redirecting to #targetURL# (#statusCode#)' ); try { - session._fw1_trace = request._fw1.trace; + sessionWrite( '_fw1_trace', request._fw1.trace ); } catch ( any _ ) { // ignore exception if session is not enabled } @@ -1132,7 +1177,7 @@ component { if ( request._fw1.doTrace ) { internalFrameworkTrace( 'redirecting to #targetURL# (#statusCode#)' ); try { - session._fw1_trace = request._fw1.trace; + sessionWrite( '_fw1_trace', request._fw1.trace ); } catch ( any _ ) { // ignore exception if session is not enabled } @@ -1204,6 +1249,32 @@ component { return builder; } + public void function sessionDefault( string keyname, any defaultValue ) { + param name="session['#keyname#']" default="#defaultValue#"; + } + + public void function sessionDelete( string keyname ) { + structDelete( session, keyname ); + } + + public boolean function sessionHas( string keyname ) { + return structKeyExists( session, keyname ); + } + + public void function sessionLock( required function callback ) { + lock scope="session" type="exclusive" timeout="30" { + callback(); + } + } + + public any function sessionRead( string keyname ) { + return session[ keyname ]; + } + + public void function sessionWrite( string keyname, any keyvalue ) { + session[ keyname ] = keyvalue; + } + /* * call this from your setupApplication() method to tell the framework * about your bean factory - only assumption is that it supports: @@ -1356,8 +1427,7 @@ component { if ( beanFactory.containsBean( property ) ) { var args = { }; args[ property ] = beanFactory.getBean( property ); - // cfc['set'&property](argumentCollection = args) does not work on ACF9 - evaluate( 'cfc.set#property#( argumentCollection = args )' ); + invoke( cfc, "set#property#", args ); } } } @@ -1500,7 +1570,7 @@ component { if ( structKeyExists( cfc, method ) ) { try { internalFrameworkTrace( 'calling #lifecycle# controller', tuple.subsystem, tuple.section, method ); - evaluate( 'cfc.#method#( rc = request.context, headers = request._fw1.headers )' ); + invoke( cfc, method, { rc : request.context, headers : request._fw1.headers } ); } catch ( any e ) { setCfcMethodFailureInfo( cfc, method ); rethrow; @@ -1508,7 +1578,7 @@ component { } else if ( structKeyExists( cfc, 'onMissingMethod' ) ) { try { internalFrameworkTrace( 'calling #lifecycle# controller (via onMissingMethod)', tuple.subsystem, tuple.section, method ); - evaluate( 'cfc.#method#( rc = request.context, method = lifecycle, headers = request._fw1.headers )' ); + invoke( cfc, method, { rc : request.context, method : lifecycle, headers : request._fw1.headers } ); } catch ( any e ) { setCfcMethodFailureInfo( cfc, method ); rethrow; @@ -1545,14 +1615,14 @@ component { if ( early ) { writeOutput( '

    Exception occured before FW/1 was initialized

    '); } else { - writeOutput( '' & ( indirect ? 'Original exception ' : 'Exception' ) & ' in #event#' ); + writeOutput( '' & ( indirect ? 'Original exception ' : 'Exception' ) & ' in #encodeForHTML(event)#' ); if ( structKeyExists( request, 'failedAction' ) ) { - writeOutput( '

    The action #request.failedAction# failed.

    ' ); + writeOutput( '

    The action #encodeForHtml(request.failedAction)# failed.

    ' ); } - writeOutput( '#exception.message#' ); + writeOutput( '#encodeForHtml(exception.message)#' ); } - writeOutput( '

    #exception.detail# (#exception.type#)

    ' ); + writeOutput( '

    #encodeForHtml(exception.detail)# (#encodeForHtml(exception.type)#)

    ' ); dumpException(exception); } @@ -1720,26 +1790,6 @@ component { if ( structKeyExists( cfc, 'init' ) ) { cfc.init( this ); } - } else if ( cachedFileExists( cfcFilePath( request.cfcbase ) & subsystemDir & controllersSlash & section & '.lc' ) ) { - // we call createObject() rather than new so we can control initialization: - if ( request.cfcbase == '' ) { - cfc = createObject( 'component', subsystemDot & controllersDot & section ); - } else { - cfc = createObject( 'component', request.cfcbase & '.' & subsystemDot & controllersDot & section ); - } - if ( structKeyExists( cfc, 'init' ) ) { - cfc.init( this ); - } - } else if ( cachedFileExists( cfcFilePath( request.cfcbase ) & subsystemDir & controllersSlash & section & '.lucee' ) ) { - // we call createObject() rather than new so we can control initialization: - if ( request.cfcbase == '' ) { - cfc = createObject( 'component', subsystemDot & controllersDot & section ); - } else { - cfc = createObject( 'component', request.cfcbase & '.' & subsystemDot & controllersDot & section ); - } - if ( structKeyExists( cfc, 'init' ) ) { - cfc.init( this ); - } } if ( isObject( cfc ) && ( hasDefaultBeanFactory() || hasSubsystemBeanFactory( subsystem ) ) ) { autowire( cfc, getBeanFactory( subsystem ) ); @@ -1778,27 +1828,25 @@ component { var nextPreserveKey = ''; var oldKeyToPurge = ''; try { - if ( variables.framework.maxNumContextsPreserved > 1 ) { - lock scope="session" type="exclusive" timeout="30" { - param name="session.__fw1NextPreserveKey" default="1"; - nextPreserveKey = session.__fw1NextPreserveKey; - session.__fw1NextPreserveKey = session.__fw1NextPreserveKey + 1; - } - oldKeyToPurge = nextPreserveKey - variables.framework.maxNumContextsPreserved; - } else { - lock scope="session" type="exclusive" timeout="30" { - session.__fw1PreserveKey = ''; - nextPreserveKey = session.__fw1PreserveKey; + sessionLock(function(){ + if ( variables.framework.maxNumContextsPreserved > 1 ) { + sessionDefault( '__fw1NextPreserveKey', 1 ); + nextPreserveKey = sessionRead( '__fw1NextPreserveKey' ); + sessionWrite( '__fw1NextPreserveKey', nextPreserveKey + 1 ); + oldKeyToPurge = nextPreserveKey - variables.framework.maxNumContextsPreserved; + } else { + nextPreserveKey = ''; + sessionWrite( '__fw1PreserveKey', nextPreserveKey ); + oldKeyToPurge = ''; } - oldKeyToPurge = ''; + }); + var key = getPreserveKeySessionKey( oldKeyToPurge ); + if ( sessionHas( key ) ) { + sessionDelete( key ); } } catch ( any e ) { // ignore - assume session scope is disabled } - var key = getPreserveKeySessionKey( oldKeyToPurge ); - if ( structKeyExists( session, key ) ) { - structDelete( session, key ); - } return nextPreserveKey; } @@ -1807,7 +1855,7 @@ component { } private any function getProperty( struct cfc, string property ) { - if ( structKeyExists( cfc, 'get#property#' ) ) return evaluate( 'cfc.get#property#()' ); + if ( structKeyExists( cfc, 'get#property#' ) ) return invoke( cfc, "get#property#" ); } private string function getSubsystemDirPrefix( string subsystem ) { @@ -1829,17 +1877,16 @@ component { // allow alternative spellings args.fw = this; args.fw1 = this; - evaluate( 'cfc.setFramework( argumentCollection = args )' ); + cfc.setFramework( argumentCollection = args ); } } private void function internalFrameworkTrace( string message, string subsystem = '', string section = '', string item = '', string traceType = 'INFO' ) { if ( request._fw1.doTrace ) { try { - if ( isDefined( 'session._fw1_trace' ) && - structKeyExists( session, '_fw1_trace' ) ) { - request._fw1.trace = session._fw1_trace; - structDelete( session, '_fw1_trace' ); + if ( sessionHas( '_fw1_trace' ) ) { + request._fw1.trace = sessionRead( '_fw1_trace' ); + sessionDelete( '_fw1_trace' ); } } catch ( any _ ) { // ignore if session is not enabled @@ -1855,9 +1902,13 @@ component { if ( structKeyExists( rc, '$' ) ) { $ = rc.$; } - var response = ''; - savecontent variable="response" { - include '#layoutPath#'; + local.body = body; + var response = customTemplateEngine( 'layout', layoutPath, local ); + if ( isNull( response ) ) { + response = ''; + savecontent variable="response" { + include '#layoutPath#'; + } } return response; } @@ -1870,9 +1921,12 @@ component { $ = rc.$; } structAppend( local, args ); - var response = ''; - savecontent variable="response" { - include '#viewPath#'; + var response = customTemplateEngine( 'view', viewPath, local ); + if ( isNull( response ) ) { + response = ''; + savecontent variable="response" { + include '#viewPath#'; + } } return response; } @@ -1955,13 +2009,6 @@ component { pathInfo.base = pathInfo.base & getSubsystemDirPrefix( subsystem ); } var defaultPath = pathInfo.base & folder & 's/' & pathInfo.path & '.cfm'; - if ( !cachedFileExists( defaultPath ) ) - defaultPath = pathInfo.base & folder & 's/' & pathInfo.path & '.lucee'; - if ( !cachedFileExists( defaultPath ) ) - defaultPath = pathInfo.base & folder & 's/' & pathInfo.path & '.lc'; - if ( !cachedFileExists( defaultPath ) ) - // can't find it so assume .cfm default value - defaultPath = pathInfo.base & folder & 's/' & pathInfo.path & '.cfm'; return customizeViewOrLayoutPath( pathInfo, type, defaultPath ); } @@ -2268,8 +2315,8 @@ component { var preserveKeySessionKey = getPreserveKeySessionKey( '' ); } try { - if ( structKeyExists( session, preserveKeySessionKey ) ) { - structAppend( request.context, session[ preserveKeySessionKey ], false ); + if ( sessionHas( preserveKeySessionKey ) ) { + structAppend( request.context, sessionRead( preserveKeySessionKey ), false ); if ( variables.framework.maxNumContextsPreserved == 1 ) { /* When multiple contexts are preserved, the oldest context is purged @@ -2277,7 +2324,7 @@ component { This allows for a browser refresh after the redirect to still receive the same context. */ - structDelete( session, preserveKeySessionKey ); + sessionDelete( preserveKeySessionKey ); } } } catch ( any e ) { @@ -2288,17 +2335,22 @@ component { private string function saveFlashContext( string keys ) { var curPreserveKey = getNextPreserveKeyAndPurgeOld(); var preserveKeySessionKey = getPreserveKeySessionKey( curPreserveKey ); + var tmpSession = ''; try { - param name="session.#preserveKeySessionKey#" default="#{ }#"; + sessionDefault( preserveKeySessionKey, {} ); if ( keys == 'all' ) { - structAppend( session[ preserveKeySessionKey ], request.context ); + tmpSession = sessionRead( preserveKeySessionKey ); + structAppend( tmpSession, request.context ); + sessionWrite( preserveKeySessionKey, tmpSession ); } else { var key = 0; var keyNames = listToArray( keys ); for ( key in keyNames ) { key = trim( key ); if ( structKeyExists( request.context, key ) ) { - session[ preserveKeySessionKey ][ key ] = request.context[ key ]; + tmpSession = sessionRead( preserveKeySessionKey ); + tmpSession[ key ] = request.context[ key ]; + sessionWrite( preserveKeySessionKey, tmpSession); } else { internalFrameworkTrace( message = 'key "#key#" does not exist in RC, cannot preserve.', traceType = 'WARNING' ); } @@ -2334,7 +2386,7 @@ component { if ( !isNull( obj ) ) setProperty( obj, newProperty, args ); } } else { - evaluate( 'cfc.set#property#( argumentCollection = args )' ); + invoke( cfc, "set#property#", args ); } } @@ -2480,6 +2532,10 @@ component { if ( !structKeyExists(variables.framework, 'baseURL') ) { variables.framework.baseURL = 'useCgiScriptName'; } + // remove trailing "/" from baseURL + if ( len( variables.framework.baseURL ) > 1 && right( variables.framework.baseURL, 1 ) == '/' ) { + variables.framework.baseURL = left( variables.framework.baseURL, len( variables.framework.baseURL ) - 1 ); + } if ( !structKeyExists(variables.framework, 'generateSES') ) { variables.framework.generateSES = false; } @@ -2488,8 +2544,7 @@ component { } // NOTE: unhandledExtensions is a list of file extensions that are not handled by FW/1 if ( !structKeyExists(variables.framework, 'unhandledExtensions') ) { - // NOTE: this prevents index.lc or index.lucee from working!! - variables.framework.unhandledExtensions = 'cfc,lc,lucee'; + variables.framework.unhandledExtensions = 'cfc'; } // NOTE: you can provide a comma delimited list of paths. Since comma is the delim, it can not be part of your path URL to exclude if ( structKeyExists(variables.framework, 'unhandledPaths') ) { @@ -2776,7 +2831,6 @@ component { } // certain remote calls do not have URL or form scope: if ( isDefined( 'URL' ) ) structAppend( request.context, URL ); - if ( isDefined( 'form' ) ) structAppend( request.context, form ); var httpData = getHttpRequestData(); if ( variables.framework.decodeRequestBody ) { // thanks to Adam Tuttle and by proxy Jason Dean and Ray Camden for the @@ -2802,7 +2856,13 @@ component { var paramPairs = listToArray( body, "&" ); for ( var pair in paramPairs ) { var parts = listToArray( pair, "=", true ); // handle blank values - request.context[ parts[ 1 ] ] = urlDecode( parts[ 2 ] ); + var keyName = parts[ 1 ]; + var keyValue = urlDecode( parts[ 2 ] ); + if ( !structKeyExists( request.context, keyName ) ) { + request.context[ keyName ] = keyValue; + } else { + request.context[ keyName ] = listAppend( request.context[ keyName ], keyValue ); + } } } catch ( any e ) { throw( type = "FW1.JSONPOST", @@ -2815,6 +2875,7 @@ component { } } } + if ( isDefined( 'form' ) ) structAppend( request.context, form ); request._fw1.headers = httpData.headers; // figure out the request action before restoring flash context: if ( !structKeyExists( request.context, variables.framework.action ) ) { diff --git a/introduction/views/main/examples.cfm b/introduction/views/main/examples.cfm index 7b40eb3f..28624312 100644 --- a/introduction/views/main/examples.cfm +++ b/introduction/views/main/examples.cfm @@ -7,16 +7,21 @@ + rc.files.name is not 'layouts' and rc.files.name is not 'views' and + rc.files.name is not 'subsystems'>
  • #rc.files.name# - - - will not work with a non-empty context root! - - - - requires /examples/todos/index.cfm/* as a wildcard pattern for Tomcat! - + + + - requires Java 8! + + + - will not work with a non-empty context root! + + + - requires /examples/todos/index.cfm/* as a wildcard pattern for Tomcat! + +
  • diff --git a/introduction/views/main/missingview.cfm b/introduction/views/main/missingview.cfm new file mode 100644 index 00000000..5aa6fdd5 --- /dev/null +++ b/introduction/views/main/missingview.cfm @@ -0,0 +1,2 @@ +I'm sorry, but no such view is available! + diff --git a/run-tests-example.sh b/run-tests-example.sh deleted file mode 100755 index ce2fb21b..00000000 --- a/run-tests-example.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# DO NOT MODIFY THIS FILE! -# -# COPY IT TO run-tests.sh AND MODIFY IT TO MATCH YOUR LOCAL -# ENVIRONMENT: test.path.root should be the file system path to your -# local repo, which should be an active web root for your CFML engine; -# server.name should be the local DNS entry that points to this -# project; server.port should be the local port you use for this -# project; You will need MXUnit (and WireBox I think) installed in -# this project's webroot (they are ignored by Git). - -ant -Dplatform=railo41 -Dtest.path.root=/Developer/workspace/fw1 \ - -Dcontext.root= -Dserver.name=fw1.local -Dserver.port=8080 \ - run-tests-mxunit diff --git a/server.json b/server.json new file mode 100644 index 00000000..a959a464 --- /dev/null +++ b/server.json @@ -0,0 +1,11 @@ +{ + "app":{ + "cfengine":"lucee@5" + }, + "web":{ + "http":{ + "port":"8500" + } + }, + "openbrowser":"false" +} \ No newline at end of file diff --git a/tests/AddBeanTest.cfc b/tests/AddBeanTest.cfc index 9937d57c..e1e11993 100644 --- a/tests/AddBeanTest.cfc +++ b/tests/AddBeanTest.cfc @@ -6,15 +6,15 @@ component extends="mxunit.framework.TestCase" { .declare( "known" ).asValue( 42 ).done(); } - function shouldHaveKnownValue() { + function testHaveKnownValue() { assertEquals( 42, variables.added.getBean( "known" ) ); } - function shouldBeSingleton() { + function testBeSingleton() { assertTrue( variables.added.isSingleton( "known" ) ); } - function shouldHaveKnownMetadata() { + function testHaveKnownMetadata() { var info = variables.added.getBeanInfo( "known" ); assertEquals( 42, info.value ); assertTrue( info.isSingleton ); diff --git a/tests/Application.cfc b/tests/Application.cfc index 2120ce9b..bf55b707 100644 --- a/tests/Application.cfc +++ b/tests/Application.cfc @@ -1,8 +1,8 @@ component{ this.name = 'fw1 test'; - variables.here = getDirectoryFromPath(getCurrentTemplatePath()); - this.mappings['/mxunit'] = variables.here & "../../mxunit"; + variables.here = getDirectoryFromPath(getCurrentTemplatePath()); + this.mappings['/mxunit'] = variables.here & "../testbox/system/compat"; this.mappings['/framework'] = variables.here & "../framework"; this.mappings['/tests'] = variables.here; - this.mappings['/goldfish/trumpets'] = variables.here & "extrabeans"; + this.mappings['/goldfish/trumpets'] = variables.here & "extrabeans"; } diff --git a/tests/BeanInfoTest.cfc b/tests/BeanInfoTest.cfc index 68b0b7c3..45a185a9 100644 --- a/tests/BeanInfoTest.cfc +++ b/tests/BeanInfoTest.cfc @@ -4,14 +4,14 @@ component extends="mxunit.framework.TestCase" { variables.factory = new framework.ioc( "" ); } - function shouldBeAStruct() { + function testBeAStruct() { var info = variables.factory.getBeanInfo(); assertTrue( isStruct( info ) ); assertEquals( 1, structCount( info ) ); assertEquals( "beaninfo", structKeyList( info ) ); } - function shouldContainMetadata() { + function testContainMetadata() { var info = variables.factory.getBeanInfo( "beanfactory" ); assertTrue( isStruct( info ) ); assertEquals( 2, structCount( info ) ); @@ -19,7 +19,7 @@ component extends="mxunit.framework.TestCase" { assertTrue( info.isSingleTon ); } - function shouldContainParent() { + function testContainParent() { var parent = new framework.ioc( "" ); variables.factory.setParent( parent ); var info = variables.factory.getBeanInfo(); @@ -27,7 +27,7 @@ component extends="mxunit.framework.TestCase" { assertTrue( structKeyExists( info.parent, "beaninfo" ) ); } - function shouldBeFlat() { + function testBeFlat() { var parent = new framework.ioc( "" ); parent.declare( "father" ).asValue( "figure" ); variables.factory.setParent( parent ); @@ -37,7 +37,7 @@ component extends="mxunit.framework.TestCase" { assertTrue( structKeyExists( info.beaninfo, "father" ) ); } - function shouldMatchRegex() { + function testMatchRegex() { variables.factory .declare( "father" ).asValue( "figure" ).done() .addBean( "mother", "figure" ); @@ -56,7 +56,7 @@ component extends="mxunit.framework.TestCase" { } - function shouldMatchRegexWithParent() { + function testMatchRegexWithParent() { variables.factory.addBean( "father", "figure" ); var parent = new framework.ioc( "" ); variables.factory.setParent( parent ); diff --git a/tests/CircularTest.cfc b/tests/CircularTest.cfc index 0ab68b98..65ed679c 100644 --- a/tests/CircularTest.cfc +++ b/tests/CircularTest.cfc @@ -1,6 +1,6 @@ component extends="mxunit.framework.TestCase" { - function shouldResolveCircular() { + function testResolveCircular() { var bf = new framework.ioc( "/tests/circular" ); var a = bf.getBean( "a" ); var b = bf.getBean( "b" ); @@ -14,7 +14,7 @@ component extends="mxunit.framework.TestCase" { assertFalse( structKeyExists( b, "name" ) ); } - function shouldResolveAndConfigureCircular() { + function testResolveAndConfigureCircular() { var bf = new framework.ioc( "/tests/circular", { initMethod = "configure" } ); var a = bf.getBean( "a" ); var b = bf.getBean( "b" ); diff --git a/tests/ConstantTest.cfc b/tests/ConstantTest.cfc index 174ca29f..fde91774 100644 --- a/tests/ConstantTest.cfc +++ b/tests/ConstantTest.cfc @@ -4,15 +4,15 @@ component extends="mxunit.framework.TestCase" { variables.constants = new framework.ioc( "", { constants = { known = 42 } } ); } - function shouldHaveKnownValue() { + function testHaveKnownValue() { assertEquals( 42, variables.constants.getBean( "known" ) ); } - function shouldBeSingleton() { + function testBeSingleton() { assertTrue( variables.constants.isSingleton( "known" ) ); } - function shouldHaveKnownMetadata() { + function testHaveKnownMetadata() { var info = variables.constants.getBeanInfo( "known" ); assertEquals( 42, info.value ); assertTrue( info.isSingleton ); diff --git a/tests/DeclareBeanTest.cfc b/tests/DeclareBeanTest.cfc index 0f0df62c..1cf70e8b 100644 --- a/tests/DeclareBeanTest.cfc +++ b/tests/DeclareBeanTest.cfc @@ -1,6 +1,6 @@ component extends="mxunit.framework.TestCase" { - function shouldDeclareSingleton() { + function testDeclareSingleton() { var bf = new framework.ioc( "" ) .declare( "foo" ).instanceOf( "tests.extrabeans.sheep.item" ).done(); structDelete( application, "itemCount" ); @@ -11,7 +11,7 @@ component extends="mxunit.framework.TestCase" { assertSame( item1, item2 ); } - function shouldDeclareTransient() { + function testDeclareTransient() { var bf = new framework.ioc( "" ) .declare( "foo" ) .instanceOf( "tests.extrabeans.sheep.item" ) @@ -25,7 +25,7 @@ component extends="mxunit.framework.TestCase" { assertNotSame( item1, item2 ); } - function shouldDeclareSingletonWithOverride() { + function testDeclareSingletonWithOverride() { var bf = new framework.ioc( "" ) .declare( "foo" ) .instanceOf( "tests.extrabeans.sheep.item" ) @@ -39,7 +39,7 @@ component extends="mxunit.framework.TestCase" { assertSame( item1, item2 ); } - function shouldDeclareTransientWithOverride() { + function testDeclareTransientWithOverride() { var bf = new framework.ioc( "" ) .declare( "foo" ) .instanceOf( "tests.extrabeans.sheep.item" ) @@ -54,7 +54,7 @@ component extends="mxunit.framework.TestCase" { assertNotSame( item1, item2 ); } - function shouldDeclareAndAdd() { + function testDeclareAndAdd() { var bf = new framework.ioc( "", { omitTypedProperties = false } ) .declare( "foo" ).instanceOf( "tests.declared.things.myconfig" ).done() .declare( "name" ).asValue( "test" ).done() @@ -64,7 +64,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( "some", item.getConfig() ); } - function shouldDeclareWithOverride() { + function testDeclareWithOverride() { var bf = new framework.ioc( "", { omitTypedProperties = false } ) .declare( "foo" ) .instanceOf( "tests.declared.things.myconfig" ) @@ -75,7 +75,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( "some", item.getConfig() ); } - function shouldDeclareInteractWithDefault() { + function testDeclareInteractWithDefault() { var bf = new framework.ioc( "", { omitDefaultedProperties = false } ).declareBean( "foo", "tests.declared.things.myconfig" ) .addBean( "dftname", "injected" ); var item = bf.getBean( "foo" ); diff --git a/tests/DisableLayoutTest.cfc b/tests/DisableLayoutTest.cfc index 80bd1bce..3668372f 100644 --- a/tests/DisableLayoutTest.cfc +++ b/tests/DisableLayoutTest.cfc @@ -10,7 +10,6 @@ component extends="tests.InjectableTest" { } function testEnabledLayout() { - variables.fw.enableLayout(); var output = ""; variables.fw.onRequestStart( "" ); savecontent variable="output" { @@ -21,6 +20,7 @@ component extends="tests.InjectableTest" { } function testExplicitlyEnabledLayout() { + variables.fw.enableLayout(); var output = ""; variables.fw.onRequestStart( "" ); savecontent variable="output" { diff --git a/tests/EmptyTest.cfc b/tests/EmptyTest.cfc index 5ff96a3a..20cadd1c 100644 --- a/tests/EmptyTest.cfc +++ b/tests/EmptyTest.cfc @@ -4,11 +4,11 @@ component extends="mxunit.framework.TestCase" { variables.emptyFactory = new framework.ioc( "" ); } - function shouldContainBeanFactory() { + function testContainBeanFactory() { assertTrue( variables.emptyFactory.containsBean( "beanFactory" ) ); } - function shouldContainJustOneBean() { + function testContainJustOneBean() { var info = variables.emptyFactory.getBeanInfo(); assertEquals( 1, structCount( info.beaninfo ) ); assertEquals( "beanfactory", structKeyList( info.beaninfo ) ); diff --git a/tests/ExtraBeansTest.cfc b/tests/ExtraBeansTest.cfc index 8cbb7205..0737b111 100644 --- a/tests/ExtraBeansTest.cfc +++ b/tests/ExtraBeansTest.cfc @@ -1,6 +1,6 @@ component extends="mxunit.framework.TestCase" { - function shouldResolveMapping() { + function testResolveMapping() { var factory = new framework.ioc( "/tests/extrabeans" ); application.itemCount = 0; assertTrue( factory.containsBean( "item" ) ); @@ -13,7 +13,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( 1, application.itemCount ); } - function shouldResolveMappingWithSingular() { + function testResolveMappingWithSingular() { var factory = new framework.ioc( "/tests/extrabeans", { singulars = { sheep = "bean" } } ); application.itemCount = 0; @@ -27,7 +27,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( 2, application.itemCount ); } - function shouldNotInjectTypedProperty() { + function testNotInjectTypedProperty() { structDelete( application, "itemCount" ); variables.factory = new framework.ioc( "/tests/model, /tests/extrabeans", { singulars = { sheep = "lamb" }, diff --git a/tests/FactoryBeanTest.cfc b/tests/FactoryBeanTest.cfc index 162ec4d6..5303ee42 100644 --- a/tests/FactoryBeanTest.cfc +++ b/tests/FactoryBeanTest.cfc @@ -1,12 +1,12 @@ component extends="mxunit.framework.TestCase" { - function shouldSupportBasicFactoryMethod() { + function testSupportBasicFactoryMethod() { var bf = new framework.ioc( "/tests/model" ); bf.declare( "a" ).fromFactory( "factory", "makeMeAnA" ); assertEquals( "I am an A", bf.getBean( "a" ) ); } - function shouldSupportFactoryFunction() { + function testSupportFactoryFunction() { var bf = new framework.ioc( "/tests/model" ); bf.declare( "a" ).fromFactory( function() { return "I am an A"; @@ -14,14 +14,14 @@ component extends="mxunit.framework.TestCase" { assertEquals( "I am an A", bf.getBean( "a" ) ); } - function shouldSupportFactoryMethodViaBean() { + function testSupportFactoryMethodViaBean() { var bf = new framework.ioc( "" ); var factory = new tests.model.services.factory(); bf.factoryBean( "a", factory, "makeMeAnA" ); assertEquals( "I am an A", bf.getBean( "a" ) ); } - function shouldSupportFactoryMethodWithBeanArg() { + function testSupportFactoryMethodWithBeanArg() { var bf = new framework.ioc( "/tests/model" ); bf.declare( "a" ) .fromFactory( "factory", "makeAWithFava" ) @@ -29,7 +29,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( "I am a fava bean", bf.getBean( "a" ) ); } - function shouldSupportFactoryMethodWithLocalArg() { + function testSupportFactoryMethodWithLocalArg() { var bf = new framework.ioc( "/tests/model" ); bf.declare( "a" ) .fromFactory( "factory", "makeAWithFava" ) diff --git a/tests/InitMethodWithConstantsTest.cfc b/tests/InitMethodWithConstantsTest.cfc index 8e166d61..a694f2b8 100644 --- a/tests/InitMethodWithConstantsTest.cfc +++ b/tests/InitMethodWithConstantsTest.cfc @@ -9,12 +9,12 @@ component extends="mxunit.framework.TestCase" { } - function shouldHaveCalledConfigure () { + function testHaveCalledConfigure () { var myService = beanFactory.getBean("myService"); assertEquals( 42, myService.getResult()); } - function shouldNotConfigureConstants () { + function testNotConfigureConstants () { var constObj = beanFactory.getBean("constObj"); assertFalse( constObj.getBooleanValue() ); diff --git a/tests/InjectPropertiesTest.cfc b/tests/InjectPropertiesTest.cfc index 9d25b7d3..7582b1a5 100644 --- a/tests/InjectPropertiesTest.cfc +++ b/tests/InjectPropertiesTest.cfc @@ -5,7 +5,7 @@ component extends="mxunit.framework.TestCase" { variables.ioc2 = new framework.ioc( "/tests/model" ); } - function shouldInjectWithType() { + function testInjectWithType() { var bean = ioc.injectProperties( "tests.declared.things.myconfig", { name = "ByType" } ); assertEquals( "ByType", bean.getName() ); try { @@ -16,7 +16,7 @@ component extends="mxunit.framework.TestCase" { } } - function shouldInjectWithObject() { + function testInjectWithObject() { var bean = ioc.injectProperties( new declared.things.myconfig( "object" ), { name = "ByObject" } ); @@ -24,7 +24,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( "object", bean.getConfig() ); } - function shouldInjectWithName() { + function testInjectWithName() { variables.ioc .addBean( "data", "data" ) .declareBean( "configObject", "tests.declared.things.myconfig" ); @@ -33,7 +33,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( "data", bean.getConfig() ); } - function shouldInjectWithNullValues( numeric userid, string username ) { + function testInjectWithNullValues( numeric userid, string username ) { // use arguments to pass into bean, argument values are null var bean = variables.ioc2.injectProperties( "user2Bean", arguments ); assertEquals( "0", bean.getUserid() ); diff --git a/tests/InjectableTest.cfc b/tests/InjectableTest.cfc index 1929dc4a..a23dc3b6 100644 --- a/tests/InjectableTest.cfc +++ b/tests/InjectableTest.cfc @@ -2,6 +2,7 @@ component extends="mxunit.framework.TestCase" { private any function clearFrameworkFromRequest () { structDelete(request, "_fw1"); + structDelete(request, "layout"); } private any function getVariablesScope( any cfc ) { diff --git a/tests/MappingTest.cfc b/tests/MappingTest.cfc index 85ac163e..5cc187fc 100644 --- a/tests/MappingTest.cfc +++ b/tests/MappingTest.cfc @@ -1,6 +1,6 @@ component extends="mxunit.framework.TestCase" { - function shouldResolveMapping() { + function testResolveMapping() { var factory = new framework.ioc( "/goldfish/trumpets" ); application.itemCount = 0; assertTrue( factory.containsBean( "item" ) ); @@ -13,7 +13,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( 1, application.itemCount ); } - function shouldResolveMappingWithSingular() { + function testResolveMappingWithSingular() { var factory = new framework.ioc( "/goldfish/trumpets", { singulars = { sheep = "bean" } } ); application.itemCount = 0; @@ -28,7 +28,7 @@ component extends="mxunit.framework.TestCase" { } /* - function shouldAcceptExpandedPath() { + function testAcceptExpandedPath() { // on CI, webroot does not match current directory so this becomes // an undeducible path... var servicePath = expandPath( "/tests/services" ); @@ -41,7 +41,7 @@ component extends="mxunit.framework.TestCase" { } */ - function shouldAcceptRelativePath() { + function testAcceptRelativePath() { var servicePath = "/tests/services"; var factory = new framework.ioc( servicePath ); assertTrue( factory.containsBean( "user" ) ); diff --git a/tests/ModelServiceTest.cfc b/tests/ModelServiceTest.cfc index 7eb2ce9d..e711b594 100644 --- a/tests/ModelServiceTest.cfc +++ b/tests/ModelServiceTest.cfc @@ -5,7 +5,7 @@ component extends="mxunit.framework.TestCase" { variables.factory = new framework.ioc( "/tests/model, /tests/services", { transients = [ "fish" ] } ); } - function shouldHaveUserFishAndUserService() { + function testHaveUserFishAndUserService() { assertTrue( variables.factory.containsBean( "userFish" ) ); assertTrue( variables.factory.containsBean( "userService" ) ); assertFalse( variables.factory.containsBean( "user" ) ); @@ -14,7 +14,7 @@ component extends="mxunit.framework.TestCase" { assertNotSame( user1, user2 ); } - function shouldInjectUserServiceIntoProduct() { + function testInjectUserServiceIntoProduct() { assertEquals( 0, application.userServiceCount ); var svc1 = variables.factory.getBean( "userService" ); assertEquals( 1, application.userServiceCount ); diff --git a/tests/ModelTest.cfc b/tests/ModelTest.cfc index e220218d..a905ee50 100644 --- a/tests/ModelTest.cfc +++ b/tests/ModelTest.cfc @@ -4,13 +4,13 @@ component extends="mxunit.framework.TestCase" { variables.factory = new framework.ioc( "/tests/model", { transients = [ "fish" ] } ); } - function shouldHaveBeanServiceButNoShortForm() { + function testHaveBeanServiceButNoShortForm() { assertTrue( variables.factory.containsBean( "favaBean" ) ); assertTrue( variables.factory.containsBean( "favaService" ) ); assertFalse( variables.factory.containsBean( "fava" ) ); } - function shouldHaveProductAndProductService() { + function testHaveProductAndProductService() { assertTrue( variables.factory.containsBean( "productService" ) ); assertTrue( variables.factory.containsBean( "product" ) ); var svc1 = variables.factory.getBean( "productService" ); @@ -18,7 +18,7 @@ component extends="mxunit.framework.TestCase" { assertSame( svc1, svc2 ); } - function shouldHavePintoAndPintoBean() { + function testHavePintoAndPintoBean() { assertTrue( variables.factory.containsBean( "pintoBean" ) ); assertTrue( variables.factory.containsBean( "pinto" ) ); var bean1 = variables.factory.getBean( "pintoBean" ); @@ -26,7 +26,7 @@ component extends="mxunit.framework.TestCase" { assertNotSame( bean1, bean2 ); } - function shouldHaveUserAndUserFish() { + function testHaveUserAndUserFish() { assertTrue( variables.factory.containsBean( "userFish" ) ); assertTrue( variables.factory.containsBean( "user" ) ); var user1 = variables.factory.getBean( "userFish" ); diff --git a/tests/OnLoadTest-cf10.cfm b/tests/OnLoadTest-cf10.cfm deleted file mode 100644 index 12eda7e5..00000000 --- a/tests/OnLoadTest-cf10.cfm +++ /dev/null @@ -1,6 +0,0 @@ -var onLoadHasFired = false; -var bf = new framework.ioc("/tests/model").onLoad(function(beanFactory){ - onLoadHasFired = true; - }); -var q = bf.containsBean( "foo" ); -assertTrue( onLoadHasFired ); \ No newline at end of file diff --git a/tests/OnLoadTest.cfc b/tests/OnLoadTest.cfc index 3ab30c00..01a44b77 100644 --- a/tests/OnLoadTest.cfc +++ b/tests/OnLoadTest.cfc @@ -4,14 +4,14 @@ component extends="mxunit.framework.TestCase" { application.loadCount = 0; } - function shouldCallOnLoadListener() { + function testCallOnLoadListener() { var bf = new framework.ioc( "" ).onLoad( variables.loader ); assertEquals( 0, application.loadCount ); var q = bf.containsBean( "foo" ); assertEquals( 1, application.loadCount ); } - function shouldNotCallListenerWhenReloaded() { + function testNotCallListenerWhenReloaded() { var bf = new framework.ioc( "" ).onLoad( variables.loader ); assertEquals( 0, application.loadCount ); var q = bf.containsBean( "foo" ); @@ -20,14 +20,14 @@ component extends="mxunit.framework.TestCase" { assertEquals( 1, application.loadCount ); } - function shouldCallMultipleOnLoadListeners() { + function testCallMultipleOnLoadListeners() { var bf = new framework.ioc( "" ).onLoad( variables.loader ).onLoad( variables.loader ); assertEquals( 0, application.loadCount ); var q = bf.containsBean( "foo" ); assertEquals( 2, application.loadCount ); } - function shouldBeAbleToUseObjectListener() { + function testBeAbleToUseObjectListener() { var listener = new tests.model.services.listener(); var bf = new framework.ioc( "" ).onLoad( listener ); assertFalse( listener.isLoaded() ); @@ -35,26 +35,26 @@ component extends="mxunit.framework.TestCase" { assertTrue( listener.isLoaded() ); } - function shouldBeAbleToUseBeanListener() { + function testBeAbleToUseBeanListener() { var bf = new framework.ioc( "/tests/model" ).onLoad( "listenerService" ); var q = bf.containsBean( "foo" ); assertTrue( bf.getBean( "listener" ).isLoaded() ); } - function shouldBeAbleToUseFunctionExpressionListener() { - - if (listFirst(server.coldfusion.productVersion) >= 10) { - //splitting this out so that it doesnt break the tests when running on cf9 - include "OnLoadTest-cf10.cfm"; - } - + function testBeAbleToUseFunctionExpressionListener() { + var onLoadHasFired = false; + var bf = new framework.ioc("/tests/model").onLoad(function(beanFactory){ + onLoadHasFired = true; + }); + var q = bf.containsBean( "foo" ); + assertTrue( onLoadHasFired ); } private void function loader( any factory ) { ++application.loadCount; } - function shouldBeAbleToListenViaConfig() { + function testBeAbleToListenViaConfig() { var listener = new tests.model.services.listener(); var bf = new framework.ioc( "", { loadListener = listener } ); assertFalse( listener.isLoaded() ); diff --git a/tests/ParentTest.cfc b/tests/ParentTest.cfc index 38807ce1..a52050ce 100644 --- a/tests/ParentTest.cfc +++ b/tests/ParentTest.cfc @@ -6,36 +6,36 @@ component extends="mxunit.framework.TestCase" { variables.factory.setParent( variables.parent ); } - function shouldFindInParent() { + function testFindInParent() { assertEquals( 2, variables.factory.getBean( "two" ) ); } - function shouldFindInChild() { + function testFindInChild() { assertEquals( "I", variables.factory.getBean( "one" ) ); assertEquals( "III", variables.factory.getBean( "three" ) ); } - function shouldContainViaParent() { + function testContainViaParent() { assertTrue( variables.factory.containsBean( "two" ) ); } - function shouldGetMetadataViaParent() { + function testGetMetadataViaParent() { var info = variables.factory.getBeanInfo( "two" ); assertEquals( 2, info.value ); assertTrue( info.isSingleton ); } - function shouldBeSingletonViaParent() { + function testBeSingletonViaParent() { assertTrue( variables.factory.isSingleton( "two" ) ); } - function shouldHaveParentInMetadata() { + function testHaveParentInMetadata() { var info = variables.factory.getBeanInfo(); assertTrue( structKeyExists( info, "parent" ) ); assertEquals( variables.parent.getBeanInfo(), info.parent ); } - function shouldNotHaveParentWithRegex() { + function testNotHaveParentWithRegex() { var info = variables.factory.getBeanInfo( regex = "X" ); assertFalse( structKeyExists( info, "parent" ) ); } diff --git a/tests/TransientInjectionTest.cfc b/tests/TransientInjectionTest.cfc index 9a8d70c0..961c5887 100644 --- a/tests/TransientInjectionTest.cfc +++ b/tests/TransientInjectionTest.cfc @@ -1,8 +1,11 @@ component extends="mxunit.framework.TestCase" { - function shouldReturnWiredTransient() { + function setup() { + bf = new framework.ioc( "" ); + } + + function testReturnWiredTransient() { // issue #420 - var bf = new framework.ioc( "" ); bf.declareBean("transient", "tests.issue420.transient", false); bf.declareBean("singleton", "tests.issue420.singleton", true); @@ -19,4 +22,68 @@ component extends="mxunit.framework.TestCase" { assertTrue( isValid( "component", singleton.getBeanFactory() ), "should return ioc instance on the 2nd call" ); } + function testTransientIsInjectedAsConstructorInjectionIntoTransient() { + bf.declare( "ConstructorInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asTransient(); + bf.declare( "ConstructorDependancy" ).instanceOf( "tests.issue408.ConstructorDependancy" ).asTransient(); + + var ConstructorDependancy = bf.getBean( "ConstructorDependancy" ); + assertTrue( ConstructorDependancy.isInjected() ); + } + + function testTransientIsNotInjectedAsSetterInjectionIntoTransient() { + bf.declare( "SetterInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asTransient(); + bf.declare( "SetterDependancy" ).instanceOf( "tests.issue408.SetterDependancy" ).asTransient(); + + var SetterDependancy = bf.getBean( "SetterDependancy" ); + assertFalse( SetterDependancy.isInjected() ); + } + + function testSingletonIsInjectedAsConstructorInjectionIntoTransient() { + bf.declare( "ConstructorInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asSingleton(); + bf.declare( "ConstructorDependancy" ).instanceOf( "tests.issue408.ConstructorDependancy" ).asTransient(); + + var ConstructorDependancy = bf.getBean( "ConstructorDependancy" ); + assertTrue( ConstructorDependancy.isInjected() ); + } + + function testSingletonIsInjectedAsSetterInjectionIntoTransient() { + bf.declare( "SetterInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asSingleton(); + bf.declare( "SetterDependancy" ).instanceOf( "tests.issue408.SetterDependancy" ).asTransient(); + + var SetterDependancy = bf.getBean( "SetterDependancy" ); + assertTrue( SetterDependancy.isInjected() ); + } + + function testTransientIsInjectedAsConstructorInjectionIntoSingleton() { + bf.declare( "ConstructorInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asTransient(); + bf.declare( "ConstructorDependancy" ).instanceOf( "tests.issue408.ConstructorDependancy" ).asSingleton(); + + var ConstructorDependancy = bf.getBean( "ConstructorDependancy" ); + assertTrue( ConstructorDependancy.isInjected() ); + } + + function testTransientIsNotInjectedAsSetterInjectionIntoSingleton() { + bf.declare( "ConstructorInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asTransient(); + bf.declare( "SetterDependancy" ).instanceOf( "tests.issue408.SetterDependancy" ).asSingleton(); + + var SetterDependancy = bf.getBean( "SetterDependancy" ); + assertFalse( SetterDependancy.isInjected() ); + } + + function testSingletonIsInjectedAsSetterInjectionIntoSingleton() { + bf.declare( "SetterInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asSingleton(); + bf.declare( "SetterDependancy" ).instanceOf( "tests.issue408.SetterDependancy" ).asSingleton(); + + var SetterDependancy = bf.getBean( "SetterDependancy" ); + assertTrue( SetterDependancy.isInjected() ); + } + + function testSingletonIsInjectedAsConstructorInjectionIntoSingleton() { + bf.declare( "ConstructorInjectedBean" ).instanceOf( "tests.issue408.NoDependancies" ).asSingleton(); + bf.declare( "ConstructorDependancy" ).instanceOf( "tests.issue408.ConstructorDependancy" ).asSingleton(); + + var ConstructorDependancy = bf.getBean( "ConstructorDependancy" ); + assertTrue( ConstructorDependancy.isInjected() ); + } + } diff --git a/tests/TransientTest.cfc b/tests/TransientTest.cfc index f6613f50..9632e7c4 100644 --- a/tests/TransientTest.cfc +++ b/tests/TransientTest.cfc @@ -1,6 +1,6 @@ component extends="mxunit.framework.TestCase" { - function shouldNotInjectTransient() { + function testNotInjectTransient() { variables.factory = new framework.ioc( "/tests/model, /tests/extrabeans", { transients = [ "fish" ], singulars = { sheep = "bean" } } ); assertTrue( variables.factory.containsBean( "item" ) ); @@ -11,7 +11,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( "missing", item ); } - function shouldConstructWithTransient() { + function testConstructWithTransient() { variables.factory = new framework.ioc( "/tests/model", { transients = [ "fish", "services" ] } ); assertTrue( variables.factory.containsBean( "product" ) ); @@ -21,7 +21,7 @@ component extends="mxunit.framework.TestCase" { assertTrue( isObject( product ) ); } - function shouldInitializeWithBeans() { + function testInitializeWithBeans() { variables.factory = new framework.ioc( "/tests/model, /tests/extrabeans", { transients = [ "fish" ], singulars = { sheep = "bean" } } ) .addBean( "one", 1 ).addBean( "two", "two" ); @@ -33,7 +33,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( n1 + 1, application.itemCount ); } - function shouldInitializeWithConstructorArgs() { + function testInitializeWithConstructorArgs() { variables.factory = new framework.ioc( "/tests/model, /tests/extrabeans", { transients = [ "fish" ], singulars = { sheep = "bean" } } ) .addBean( "one", 1 ).addBean( "two", "two" ); @@ -45,7 +45,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( n1, application.itemCount ); } - function shouldInitializeWithOnlyConstructorArgs() { + function testInitializeWithOnlyConstructorArgs() { variables.factory = new framework.ioc( "/tests/extrabeans", { singulars = { sheep = "bean" } } ); var i = variables.factory.getBean( "item" ); diff --git a/tests/ci/HttpAntRunner.cfc b/tests/ci/HttpAntRunner.cfc deleted file mode 100644 index 1633d332..00000000 --- a/tests/ci/HttpAntRunner.cfc +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - if(arguments.type is "testcase"){ - suite = createObject("component","mxunit.framework.TestSuite").TestSuite(); - suite.addAll(arguments.value); - results = suite.run(); - } - if(arguments.type is "dir"){ - //To Do: add args for recursion, includes, and excludes - if(not isBoolean(arguments.recurse)){ - arguments.recurse = false; - } - - results = createObject("component","mxunit.runner.DirectoryTestSuite").run(directory=arguments.value, componentPath=arguments.componentPath, recurse=arguments.recurse, excludes=arguments.excludes); - } - //package name for JUnit reports - results.setPackage(arguments.packagename); - - - - - - - - - - - - - - - - - #trim(arguments.results.getHTMLResults())# - - - #trim(arguments.results.getXMLResults())# - - - #trim(arguments.results.getJUnitXMLResults())# - - #trim(arguments.results.getJUnitXMLResults())# - - - - - - - - - - - - - - - - - if(arguments.type is "testcase"){ - suite = createObject("component","mxunit.framework.TestSuite").TestSuite(); - suite.addAll(arguments.value); - results = suite.run(); - } - if(arguments.type is "dir"){ - //To Do: add args for recursion, includes, and excludes - if(not isBoolean(arguments.recurse)){ - arguments.recurse = false; - } - - results = createObject("component","DirectoryTestSuite").run(directory=arguments.value, componentPath=arguments.componentPath, recurse=arguments.recurse, excludes=arguments.excludes); - } - //package name for JUnit reports - results.setPackage(arguments.packagename); - - - - - - - - diff --git a/tests/ci/mxunit-ant.jar b/tests/ci/mxunit-ant.jar deleted file mode 100644 index 1731e2a7..00000000 Binary files a/tests/ci/mxunit-ant.jar and /dev/null differ diff --git a/tests/ci/mxunit-output-ant.jar b/tests/ci/mxunit-output-ant.jar deleted file mode 100644 index 69b84deb..00000000 Binary files a/tests/ci/mxunit-output-ant.jar and /dev/null differ diff --git a/tests/ci/scripts/acf9-control.sh b/tests/ci/scripts/acf9-control.sh deleted file mode 100755 index 14e40214..00000000 --- a/tests/ci/scripts/acf9-control.sh +++ /dev/null @@ -1,10 +0,0 @@ -pushd $WORK_DIR/jrun4/bin > /dev/null -case $1 in - start) - ./jrun -start cfusion>/dev/null& - ;; - stop) - ./jrun -stop cfusion>/dev/null& - ;; -esac -popd > /dev/null \ No newline at end of file diff --git a/tests/ci/scripts/ci-helper-acf.sh b/tests/ci/scripts/ci-helper-acf.sh deleted file mode 100755 index a6a4cd29..00000000 --- a/tests/ci/scripts/ci-helper-acf.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -CONTROL_SCRIPT='coldfusion10/cfusion/bin/coldfusion' - -PLATFORM_DIR="coldfusion10" -WEBROOT="coldfusion10/cfusion/wwwroot" -MY_DIR=`dirname $0` -source $MY_DIR/ci-helper-base.sh $1 $2 - -case $1 in - install) - echo "Fixing ACF install directory..." - grep -rl "/opt/coldfusion10/" --exclude-dir=$WEBROOT . | xargs -n 1 sed -i "s#/opt/coldfusion10/#$WORK_DIR/coldfusion10/#g" - - sed -i "s/8500/$SERVER_PORT/g" coldfusion10/cfusion/runtime/conf/server.xml - ;; - start|stop) - ;; - *) - echo "Usage: $0 {install|start|stop}" - exit 1 - ;; -esac - -exit 0 \ No newline at end of file diff --git a/tests/ci/scripts/ci-helper-acf9.sh b/tests/ci/scripts/ci-helper-acf9.sh deleted file mode 100755 index dd6a3fe5..00000000 --- a/tests/ci/scripts/ci-helper-acf9.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -PLATFORM_DIR="jrun4" -WEBROOT="jrun4/servers/cfusion/cfusion-ear/cfusion-war" - -MY_DIR=`dirname $0` -CONTROL_SCRIPT="`pwd`/$MY_DIR/acf9-control.sh" - -source $MY_DIR/ci-helper-base.sh $1 $2 - -case $1 in - install) - echo "Fixing ACF install directory..." - grep -rl "/opt/jrun4/" --exclude-dir=$WEBROOT . | xargs -n 1 sed -i "s#/opt/jrun4/#$WORK_DIR/jrun4/#g" - - sed -i "s/8300/$SERVER_PORT/g" jrun4/servers/cfusion/SERVER-INF/jrun.xml - ;; - start|stop) - ;; - *) - echo "Usage: $0 {install|start|stop}" - exit 1 - ;; -esac - -exit 0 \ No newline at end of file diff --git a/tests/ci/scripts/ci-helper-base.sh b/tests/ci/scripts/ci-helper-base.sh deleted file mode 100755 index 5843f37c..00000000 --- a/tests/ci/scripts/ci-helper-base.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash -if [ ! -n "$WORK_DIR" ]; then - echo "WORK_DIR must be set!" - exit 1 -fi - -if [ ! -n "$BUILD_DIR" ]; then - BUILD_DIR=`pwd` -fi - -echo "Working directory: $WORK_DIR, Build directory: $BUILD_DIR" - -if [ ! "$1" == "install" ]; then - - if [ ! -d $WORK_DIR ]; then - echo "Working directory doesn't exist and this isn't an install!" - exit 1 - else - cd $WORK_DIR - fi -else - if [ ! -n "$2" ]; then - echo "usage: $0 install PROJECTNAME"; - exit 1 - fi -fi - -WGET_OPTS="-nv" - -function download_and_extract { - FILENAME=`echo $1|awk '{split($0,a,"/"); print a[length(a)]}'` - if [[ "$1" == /* ]]; then - echo "Copying $1 to $FILENAME" - cp $1 $FILENAME - else - echo "Downloading $1 to $FILENAME" - wget $WGET_OPTS $1 -O $FILENAME - fi - - if [[ "$FILENAME" == *zip ]]; then - unzip -q $FILENAME - else - tar -zxf $FILENAME - fi - rm $FILENAME - result=$FILENAME -} - - -if [ ! -n "$SERVER_PORT" ]; then - SERVER_PORT="8500" -fi - -HEALTHCHECK_URL="http://localhost:$SERVER_PORT" - - -case $1 in - install) - if [ -d $WORK_DIR ]; then - echo "Removing $WORK_DIR" - rm -rf $WORK_DIR - fi - - mkdir -p $WORK_DIR - cd $WORK_DIR - - download_and_extract $PLATFORM_URL - - # assume platform dir is the only dir - FIRST_DIR=`ls -b` - if [ "$FIRST_DIR" != "$PLATFORM_DIR" ]; then - mv $FIRST_DIR $PLATFORM_DIR - fi - download_and_extract $TESTFRAMEWORK_URL - - case $TESTFRAMEWORK in - mxunit) - mv mxunit* "$WEBROOT/$TESTFRAMEWORK" - ;; - testbox) - mv testbox "$WEBROOT/$TESTFRAMEWORK" - ;; - esac - ln -s $BUILD_DIR $WEBROOT/$2 - ;; - start) - if [ ! -f $CONTROL_SCRIPT ]; then - echo "Control script does not exist!" - exit 1 - fi - echo "Starting server... ($HEALTHCHECK_URL)" - $CONTROL_SCRIPT start& - until [ "`curl --connect-timeout 2 -m 2 -s -o /dev/null -w "%{http_code}" $HEALTHCHECK_URL`" == "200" ] - do - echo "Waiting for server to start..." - sleep 2 - done - ;; - stop) - echo "Stopping server..." - $CONTROL_SCRIPT stop - while curl --connect-timeout 2 --max-time 2 -s $HEALTHCHECK_URL>/dev/null - do - echo "Waiting for server to stop..." - sleep 1 - done - ;; - *) - echo "Usage: $0 {install|start|stop}" - exit 1 - ;; -esac \ No newline at end of file diff --git a/tests/ci/scripts/ci-helper-railo.sh b/tests/ci/scripts/ci-helper-railo.sh deleted file mode 100755 index 4941796e..00000000 --- a/tests/ci/scripts/ci-helper-railo.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -set -e - -case $1 in - start) - CONTROL_SCRIPT='railo/start' - ;; - stop) - CONTROL_SCRIPT='railo/stop' - ;; -esac - -PLATFORM_DIR="railo" -WEBROOT="railo/webapps/www" -MY_DIR=`dirname $0` -source $MY_DIR/ci-helper-base.sh $1 $2 - -case $1 in - install) - chmod a+x railo/start - chmod a+x railo/stop - - sed -i "s/jetty.port=8888/jetty.port=$SERVER_PORT/g" railo/start - sed -i "s/STOP.PORT=8887/STOP.PORT=$STOP_PORT/g" railo/start - sed -i "s/STOP.PORT=8887/STOP.PORT=$STOP_PORT/g" railo/stop - ;; - start|stop) - ;; - *) - echo "Usage: $0 {install|start|stop}" - exit 1 - ;; -esac - -exit 0 \ No newline at end of file diff --git a/tests/defaultPropertyTest.cfc b/tests/defaultPropertyTest.cfc index f05e0369..b327397a 100644 --- a/tests/defaultPropertyTest.cfc +++ b/tests/defaultPropertyTest.cfc @@ -7,7 +7,7 @@ component extends=mxunit.framework.TestCase { .done(); } - function shouldHaveDefaultValue() { + function testHaveDefaultValue() { var data = { viaNew : new tests.extrabeans.sheep.default(), viaDI1 : variables.bf.getBean( "default" ) diff --git a/tests/defaultargTest.cfc b/tests/defaultargTest.cfc index 311b25e1..6a8d2224 100644 --- a/tests/defaultargTest.cfc +++ b/tests/defaultargTest.cfc @@ -1,6 +1,6 @@ component extends="mxunit.framework.TestCase" { - - function checkDefaultInitArgWorks() { + + function testDefaultInitArgWorks() { var factory = new framework.ioc( "/tests/model", { constants = { dsn = "sample" } } ); var user37 = factory.getBean( "user37" ); assertEquals( "sample", user37.getDSN() ); @@ -11,7 +11,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( 0, user37b.getID() ); } - function checkDefaultInitArgThreeArgs() { + function testDefaultInitArgThreeArgs() { var factory = new framework.ioc( "/tests/model", { constants = { dsn = "sample" } } ); var user37c = factory.getBean( "user37c" ); @@ -27,8 +27,8 @@ component extends="mxunit.framework.TestCase" { assertEquals( "John", user37c.getName() ); } - - function checkDefaultInitArgWorksStrict() { + + function testDefaultInitArgWorksStrict() { var factory = new framework.ioc( "/tests/model", { strict = true, constants = { dsn = "sample" } } ); @@ -41,7 +41,7 @@ component extends="mxunit.framework.TestCase" { assertEquals( 0, user37b.getID() ); } - function checkDefaultInitArgThreeArgsStrict() { + function testDefaultInitArgThreeArgsStrict() { var factory = new framework.ioc( "/tests/model", { strict = true, constants = { dsn = "sample" } } ); diff --git a/tests/frameworkErrorTest.cfc b/tests/frameworkErrorTest.cfc index 56fd7138..18cb0126 100644 --- a/tests/frameworkErrorTest.cfc +++ b/tests/frameworkErrorTest.cfc @@ -24,7 +24,8 @@ component extends="mxunit.framework.TestCase" { variables.fw.onError(exception, event); }; assertEquals(request.action, ":main.error"); - assertTrue(output contains "Unable to find a view for ':main.error' action."); + assertFalse(output contains "Unable to find a view for ':main.error' action."); + assertTrue(output contains "Unable to find a view for &##x27;&##x3a;main.error&##x27;"); } /** diff --git a/tests/frameworkRouteTest.cfc b/tests/frameworkRouteTest.cfc index 5791c8f6..d6ca9bc8 100644 --- a/tests/frameworkRouteTest.cfc +++ b/tests/frameworkRouteTest.cfc @@ -110,6 +110,12 @@ component extends="tests.InjectableTest" { match = variables.fw.processRouteMatch("$*", "default.error", "/foo/test/5", "POST"); assertTrue(match.matched); + + // issue 476 : trailing EOL regex marker should prevent match (only with ^): + match = variables.fw.processRouteMatch("$GET/$", "default.error", "/foo/test/5", "GET"); + assertTrue(match.matched); + match = variables.fw.processRouteMatch("$GET^/$", "default.error", "/foo/test/5", "GET"); + assertFalse(match.matched); } public void function testRouteMatchRedirect() diff --git a/tests/issue408/ConstructorDependancy.cfc b/tests/issue408/ConstructorDependancy.cfc new file mode 100644 index 00000000..d40c40d8 --- /dev/null +++ b/tests/issue408/ConstructorDependancy.cfc @@ -0,0 +1,11 @@ +component { + + function init( constructorInjectedBean ) { + variables.constructorInjectedBean = constructorInjectedBean; + return this; + } + + function isInjected() { + return structKeyExists( variables, "constructorInjectedBean" ); + } +} diff --git a/tests/issue408/NoDependancies.cfc b/tests/issue408/NoDependancies.cfc new file mode 100644 index 00000000..9434a9ba --- /dev/null +++ b/tests/issue408/NoDependancies.cfc @@ -0,0 +1,5 @@ +component { + function init() { + return this; + } +} diff --git a/tests/issue408/SetterDependancy.cfc b/tests/issue408/SetterDependancy.cfc new file mode 100644 index 00000000..5d0e5eb2 --- /dev/null +++ b/tests/issue408/SetterDependancy.cfc @@ -0,0 +1,13 @@ +component { + function init() { + return this; + } + + function isInjected() { + return structKeyExists( variables, "SetterInjectedBean" ); + } + + function setSetterInjectedBean( SetterInjectedBean ) { + variables.SetterInjectedBean = SetterInjectedBean; + } +} diff --git a/tests/onSessionStartBuildURLTest.cfc b/tests/onSessionStartBuildURLTest.cfc index 360832ef..3e6f1834 100644 --- a/tests/onSessionStartBuildURLTest.cfc +++ b/tests/onSessionStartBuildURLTest.cfc @@ -27,7 +27,7 @@ component extends="tests.InjectableTest" { public void function testURLandURI() { variables.fw.onRequestStart("/index.cfm"); assertEquals( "useCgiScriptName", variables.fw.getBaseURL() ); - var suffix = "/tests/ci/"; + var suffix = "/tests/"; assertEquals( suffix, right( variables.fw.buildURL( action = 'main.default' ), len( suffix ) ) ); suffix &= "main/default"; @@ -38,8 +38,8 @@ component extends="tests.InjectableTest" { public void function testURLandURIempty() { variables.fwvars.framework.baseURL = "/tests/ci/"; variables.fw.onRequestStart("/index.cfm"); - assertEquals( "/tests/ci/", variables.fw.getBaseURL() ); - assertEquals( "/tests/ci/", variables.fw.buildURL( action = 'main.default' ) ); + assertEquals( "/tests/ci", variables.fw.getBaseURL() ); + assertEquals( "/tests/ci", variables.fw.buildURL( action = 'main.default' ) ); assertEquals( "/tests/ci/main/default", variables.fw.buildCustomURL( uri = '/main/default' ) ); } diff --git a/tests/rest/DecodeTest.cfc b/tests/rest/DecodeTest.cfc new file mode 100644 index 00000000..06742ef4 --- /dev/null +++ b/tests/rest/DecodeTest.cfc @@ -0,0 +1,73 @@ +component extends="mxunit.framework.TestCase" { + + function testPostFormEncodedRequestDecodesMultiField() { + var actual = doFormEncodedHTTPRequest( "POST" ); + assertEquals( "POST", actual.method ); + assertEquals( "a,b,c", actual.single ); + assertEquals( "1,2,3,40,50", actual.multi ); + } + + function testPatchFormEncodedRequestDecodesMultiField() skip="engineNotSupported" { + var actual = doFormEncodedHTTPRequest( "PATCH" ); + assertEquals( "PATCH", actual.method ); + assertEquals( "a,b,c", actual.single ); + assertEquals( "1,2,3,40,50", actual.multi ); + } + + function testPutFormEncodedRequestDecodesMultiField() { + var actual = doFormEncodedHTTPRequest( "PUT" ); + assertEquals( "PUT", actual.method ); + assertEquals( "a,b,c", actual.single ); + assertEquals( "1,2,3,40,50", actual.multi ); + } + + function testPostJSONEncodedRequestDecodesMultiField() { + var actual = doJSONEncodedHTTPRequest( "POST" ); + assertEquals( "POST", actual.method ); + assertEquals( "a,b,c", actual.single ); + assertEquals( "1,2,3,40,50", actual.multi ); + } + + function testPatchJSONRequestDecodesMultiField() skip="engineNotSupported" { + var actual = doJSONEncodedHTTPRequest( "PATCH" ); + assertEquals( "PATCH", actual.method ); + assertEquals( "a,b,c", actual.single ); + assertEquals( "1,2,3,40,50", actual.multi ); + } + + function testPutJSONRequestDecodesMultiField() { + var actual = doJSONEncodedHTTPRequest( "PUT" ); + assertEquals( "PUT", actual.method ); + assertEquals( "a,b,c", actual.single ); + assertEquals( "1,2,3,40,50", actual.multi ); + } + + + + private function doFormEncodedHTTPRequest( verb ) { + return doHTTPRequest( verb, "application/x-www-form-urlencoded", "multi=1%2C2%2C3&multi=40&multi=50&single=a%2Cb%2Cc" ); + } + + private function doJSONEncodedHTTPRequest( verb ) { + return doHTTPRequest( verb, "application/json", '{"multi": "1,2,3,40,50","single": "a,b,c"}' ); + } + + private function doHTTPRequest( verb, contentType, body ) { + var httpService = new http(); + httpService.setmethod( verb ); + httpService.setCharset( "utf-8" ); + httpService.setUrl( "http://#CGI.SERVER_NAME#:#CGI.SERVER_PORT#/examples/rest/?action=main.#verb#" ); + httpService.addParam( type = "header", name = "content-type", value = contentType ); + httpService.addParam( type = "body", value = body ); + var response = httpService.send().getPrefix().filecontent; + if ( isJson( response ) ) { + return deserializeJSON( response ); + } + fail( "expected a JSON response for #verb# #contentType#" ); + } + + function engineNotSupported() { + return server.coldfusion.productname != "Lucee" && ListFirst( server.coldfusion.productversion ) == 10; + } + +} diff --git a/tests/runner.cfm b/tests/runner.cfm new file mode 100644 index 00000000..d8d30ce1 --- /dev/null +++ b/tests/runner.cfm @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/singletonPatternTest.cfc b/tests/singletonPatternTest.cfc index a729004e..b488cbe6 100644 --- a/tests/singletonPatternTest.cfc +++ b/tests/singletonPatternTest.cfc @@ -1,16 +1,19 @@ component extends="mxunit.framework.TestCase" { - + function setup() { - /** + /** * Note that although 'BeerFactory' and 'BarService' match the singletonpattern * they are considered transients as in the beans folder - **/ + **/ transients = ['BarService','Beer','BeerFactory','Wine','Coffee','Tea','Burger','Pizza']; singletons = ['DrinksService','FoodFactory']; - + variables.factory = new framework.ioc( "/tests/singletonPattern", { singletonPattern = ".+(Service|Factory)$" } ); } - + + function testForSingletons() { + for ( var s in singletons ) checkForSingletons( s ); + } function checkForSingletons( required beanname ) dataprovider="singletons" { assertTrue( variables.factory.containsBean( arguments.beanname ) ); assertTrue( variables.factory.isSingleton( arguments.beanname ) ); @@ -18,7 +21,10 @@ component extends="mxunit.framework.TestCase" { instanceB = variables.factory.getBean( arguments.beanname ); assertSame( instanceA, instanceB ); } - + + function testForTransients() { + for ( var t in transients ) checkForTransients( t ); + } function checkForTransients( beanname ) dataprovider="transients" { //assertTrue( variables.factory.containsBean( beanname ) ); assertFalse( variables.factory.isSingleton( beanname ) ); @@ -27,7 +33,7 @@ component extends="mxunit.framework.TestCase" { assertNotSame( instanceA, instanceB ); } - function checkPatternsAreExclusive() { + function testPatternsAreExclusive() { try { var bad = new framework.ioc( '', { singletonPattern = '', transientPattern = '' } ); fail( 'Both arguments were allowed' ); diff --git a/tests/transientPatternTest.cfc b/tests/transientPatternTest.cfc index ab4fc762..e8d525bd 100644 --- a/tests/transientPatternTest.cfc +++ b/tests/transientPatternTest.cfc @@ -1,12 +1,15 @@ component extends="mxunit.framework.TestCase" { - + function setup() { transients = ['BarService','Beer','BeerFactory','Wine','CoffeeFoo','PizzaFoo']; singletons = ['Drinks','Tea','Burger','FoodFactory']; - + variables.factory = new framework.ioc( "/tests/transientPattern", { transientPattern = ".+(Foo)$" } ); } - + + function testForSingletons() { + for ( var s in singletons ) checkForSingletons( s ); + } function checkForSingletons( required beanname ) dataprovider="singletons" { assertTrue( variables.factory.containsBean( arguments.beanname ) ); assertTrue( variables.factory.isSingleton( arguments.beanname ) ); @@ -14,7 +17,10 @@ component extends="mxunit.framework.TestCase" { instanceB = variables.factory.getBean( arguments.beanname ); assertSame( instanceA, instanceB ); } - + + function testForTransients() { + for ( var t in transients ) checkForTransients( t ); + } function checkForTransients( beanname ) dataprovider="transients" { //assertTrue( variables.factory.containsBean( beanname ) ); assertFalse( variables.factory.isSingleton( beanname ) );