Making Modules

Making Modules

Discover why ColdBox Modules are awesome and how you can go quickly from idea to ForgeBox

Cbddee54e0016667b9bcb0fdec4ab21e?s=128

Eric Peterson

July 20, 2017
Tweet

Transcript

  1. Making Modules

  2. What this talk is — An overview of modules —

    Module + ColdBox superpowers — Testing strategies for modules — Ways to quickly go from idea to ForgeBox
  3. Other Sessions Ge!ing Started with Docker Mark Drew — NPC

    Ballroom Building Progressive Web Apps Using CFML Miles Rausch — Conference Rooms
  4. Who am I? Eric Peterson ! Utah " O.C. Tanner

    " Ortus Solutions # Maintainer of ColdBox Elixir and ForgeBox.io $ Prolific Package Author % 1 wife, 2 kids
  5. What are Modules?

  6. Reusable packages of functionality.

  7. /** * Returns the character at a certain position in

    a string. * * @param str String to be checked. * @param pos Position to get character from. * @return Returns a character. * @author Raymond Camden (ray@camdenfamily.com) * @version 1, December 3, 2001 */ function CharAt(str,pos) { return Mid(str,pos,1); } — From CFLib
  8. CFMLParser — By Pete Freitag

  9. // instantiate it directly new modules.CFMLParser.File( ... ); // or

    register it in WireBox binder.map( "File@CFMLParser" ).to( "modules.CFMLParser.File" );
  10. Benefits of Modules — Reusability — Versioning — Smaller testing

    footprint — Dependency management
  11. What are good candidates for modules? Module Short Description coldbox

    Full MVC Framework testbox Testing Framework javaloader Java Class Loader str String Utility Library cbtemplate-advanced-script Application Template contentbox Full CMS integrated Integration Testing Plugin semver Semantic Versioning Utility Library rollbar Rollbar LogBox appender ses-on-request Automatically sets the SES URL on every request cfcollection Functional Programming Library
  12. Why Use Modules? — Don't repeat yourself — Don't reinvent

    the wheel — Automatic configuration — Benefit from and give back to the community — Semantic Versioning
  13. Do Modules Require ColdBox?

  14. Do Modules Require ColdBox? No...

  15. What do you get in non-ColdBox applications? — Versioning —

    Dependency management — Installation location by convention (or setting)
  16. What do you need to make a module?

  17. box.json

  18. box.json Describes your project — Version — Dependencies — Module

    type — Installation data — Package scripts — Other metadata
  19. Aside: Package Scripts

  20. Package Scripts — Run arbitrary scripts with run-script "scripts":{ "generateAPIDocs":"docbox

    generate \ mapping=qb \ excludes=test|ModuleConfig \ strategy-outputDir=docs/apidocs \ strategy-projectTitle=qb", "commitAPIDocs":"run-script generateAPIDocs &&\ !git add docs/apidocs/* && \ !git commit -m 'Updated API Docs'" }
  21. Package Scripts Hook in to CommandBox interception points "scripts":{ "postVersion":"package

    set location='elpete/qb#v`package version`'", "onRelease":"run-script commitAPIDocs && publish", "postPublish":"!git push && !git push --tags" } — Publish with one bump command.
  22. Do Modules Require ColdBox? No...

  23. Do Modules Require ColdBox? No... But...

  24. ColdBox + Modules = Super Powers!

  25. Self-contained ColdBox applications — models — interceptors — layouts &

    views — handlers — settings
  26. What do you get in ColdBox applications? — Full MVC

    subapplication — Automatic WireBox mapping — Automatic Interceptors — Overridable settings
  27. Introducing ModuleConfig.cfc

  28. ModuleConfig.cfc Properties Some of them... Property Purpose name The unique

    name of the module entryPoint The default route into this module. (i.e. api/ v1) autoMapModels Set to true to have WireBox automatically map your models folder dependencies Other dependencies that must be loaded before this one parseParentSettings Set to true to allow overrides from config/ ColdBox.cfc
  29. ModuleConfig.cfc Methods Method Purpose configure() Only interact with this module.

    Use onLoad() for cross-module, cross- framework dependencies. onLoad() When you need the framework loaded first onUnload() Undo what you did in load
  30. Bonus: ModuleConfig is also an Interceptor

  31. component { this.name = "cors"; this.author = "Eric Peterson"; this.webUrl

    = "https://github.com/elpete/cors"; function configure() {} function preProcess( event, interceptData, buffer, rc, prc ) { event.setHTTPHeader( name = "Access-Control-Allow-Origin", value = "*" ); } }
  32. To get started automatically just box install cors !

  33. Example Module redirectBack

  34. redirectBack Directory Structure

  35. redirectBack box.json (the key parts) { "name":"redirectBack", "version":"1.0.4", "location":"elpete/redirectBack#v1.0.4", "slug":"redirectBack",

    "shortDescription":"Caches the last request in the flash scope to give easy redirects back", "type":"modules", "scripts":{ "postVersion":"package set location='elpete/redirectBack#v`package version`'", "onRelease":"publish", "postPublish":"!git push && !git push --tags" }, "ignore":[ "**/.*", "test", "tests" ] }
  36. redirectBack ModuleConfig.cfc Module Properties this.title = "redirectBack"; this.author = "Eric

    Peterson"; this.webURL = "https://github.com/elpete/redirectBack"; this.description = "Caches the last request in the flash scope to give easy redirects back"; this.version = "1.0.1";
  37. redirectBack ModuleConfig.cfc configure method function configure() { /* * can

    override any of these settings in your `config/ColdBox.cfc` file. * `moduleSettings = { redirectBack = { key = "overridden_key" } };` * Or in CommandBox * `config set modules.redirectBack.key="overridden_key"` */ settings = { key = "last_url", }; interceptors = [{ class = "#moduleMapping#/interceptors/RedirectBack", name = "RedirectBack", properties = {} }]; }
  38. redirectBack ModuleConfig.cfc onLoad method function onLoad() { var helpers =

    controller.getSetting( "applicationHelper" ); arrayAppend( helpers, "#moduleMapping#/helpers/RedirectBackHelpers.cfm" ); controller.setSetting( "applicationHelper", helpers ); }
  39. redirectBack ModuleConfig.cfc onUnload method function onUnload() { controller.setSetting( "applicationHelper", arrayFilter(

    controller.getSetting( "applicationHelper" ), function( helper ) { return helper != "#moduleMapping#/helpers/RedirectBackHelpers.cfm"; } ) ); }
  40. redirectBack Review

  41. Leveraging WireBox

  42. Leveraging WireBox this.autoMapModels = true; Automatically maps all of your

    models to {modelName}@{moduleName}. property name="builder" inject="Builder@qb";
  43. Leveraging WireBox Use the full power of WireBox function configure()

    { binder.map( "DefaultGrammar" ) .to( "#moduleMapping#.models.grammars.MySQLGrammar" ); }
  44. Modules, Modules, Everywhere You don't have to be on ForgeBox

    to be a module.
  45. Git Repos Pros — Versioning (via tags) — Can be

    shareable (Public repos) — Also can be private (Private repos) Cons — No semantic version ranges. (Must specify a tag.) — Must specify the full git path (as opposed to a ForgeBox slug).
  46. UnderscoreCF

  47. modules_app Pros — Committed to your git repo — Private

    to your application — Easily contain bits of your application like API versions Cons — No easy reuse outside your project — No versioning
  48. ForgeBox CFML's NPM

  49. None
  50. None
  51. None
  52. Private Packages Coming Soon — Storage on S3 — Semantic

    Versioning — Collaborators
  53. Testing

  54. Unit Testing component extends="testbox.system.BaseSpec" { function beforeAll() { include "/root/functions/normalizeToArray.cfm";

    } function run() { describe( "normalizeToArray", function() { it( "returns an array unmodified", function() { var actual = normalizeToArray( [ 1, 2, 3, 4 ] ); expect( actual ).toBe( [ 1, 2, 3, 4 ] ); } ); it( "converts a list to an array", function() { var actual = normalizeToArray( "1,2,3,4" ); expect( actual ).toBe( [ 1, 2, 3, 4 ] ); } ); } ); } }
  55. Run your tests on all CF engines at once!

  56. TravisCI Integration language: java sudo: required jdk: - oraclejdk8 cache:

    directories: - $HOME/.CommandBox env: matrix: - ENGINE=lucee@4.5 - ENGINE=lucee@5 - ENGINE=adobe@2016 - ENGINE=adobe@11 - ENGINE=adobe@10 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 script: - box testbox run runner="http://127.0.0.1:8500/tests/runner.cfm" notifications: email: false
  57. None
  58. Scaffolding Modules

  59. Scaffolding Modules — Create box.json — Create ModuleConfig.cfc — Scaffold

    tests folder — specs folder — runner.cfm — tests/Application.cfc — Copy over .travis.yml file — Create git repo and GitHub repo. And then finally get coding....
  60. Is there an easier way?

  61. For ColdBox applications this is easy: box coldbox create app

  62. Now it is that easy for your modules: box install

    cb-module-template box module scaffold my-awesome-module "It will blow your mind!"
  63. None
  64. What this does for you: — Create box.json — Create

    ModuleConfig.cfc — Scaffold tests folder — specs folder — runner.cfm — tests/Application.cfc
  65. What this does for you: (continuted) — Copy over .travis.yml

    file — Create git repo and GitHub repo — Create a GitHub token if it doesn't exist — Sets up TravisCI to accept builds — Creates a TravisCI token if it doesn't exist So you can start coding right away
  66. Aside: The repo itself is a great example of an

    advanced module
  67. Bonus: Integration Testing your Module with ColdBox (See cborm-versioning for

    an example.)
  68. So what are you waiting for?!?

  69. Go make something awesome! !

  70. Then share it with all of us. !

  71. Thank You!! elpete @_elpete ! dev.elpete.com