Slide 1

Slide 1 text

Making Modules

Slide 2

Slide 2 text

What this talk is — An overview of modules — Module + ColdBox superpowers — Testing strategies for modules — Ways to quickly go from idea to ForgeBox

Slide 3

Slide 3 text

Other Sessions Ge!ing Started with Docker Mark Drew — NPC Ballroom Building Progressive Web Apps Using CFML Miles Rausch — Conference Rooms

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

What are Modules?

Slide 6

Slide 6 text

Reusable packages of functionality.

Slide 7

Slide 7 text

/** * 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 ([email protected]) * @version 1, December 3, 2001 */ function CharAt(str,pos) { return Mid(str,pos,1); } — From CFLib

Slide 8

Slide 8 text

CFMLParser — By Pete Freitag

Slide 9

Slide 9 text

// instantiate it directly new modules.CFMLParser.File( ... ); // or register it in WireBox binder.map( "File@CFMLParser" ).to( "modules.CFMLParser.File" );

Slide 10

Slide 10 text

Benefits of Modules — Reusability — Versioning — Smaller testing footprint — Dependency management

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Why Use Modules? — Don't repeat yourself — Don't reinvent the wheel — Automatic configuration — Benefit from and give back to the community — Semantic Versioning

Slide 13

Slide 13 text

Do Modules Require ColdBox?

Slide 14

Slide 14 text

Do Modules Require ColdBox? No...

Slide 15

Slide 15 text

What do you get in non-ColdBox applications? — Versioning — Dependency management — Installation location by convention (or setting)

Slide 16

Slide 16 text

What do you need to make a module?

Slide 17

Slide 17 text

box.json

Slide 18

Slide 18 text

box.json Describes your project — Version — Dependencies — Module type — Installation data — Package scripts — Other metadata

Slide 19

Slide 19 text

Aside: Package Scripts

Slide 20

Slide 20 text

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'" }

Slide 21

Slide 21 text

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.

Slide 22

Slide 22 text

Do Modules Require ColdBox? No...

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

ColdBox + Modules = Super Powers!

Slide 25

Slide 25 text

Self-contained ColdBox applications — models — interceptors — layouts & views — handlers — settings

Slide 26

Slide 26 text

What do you get in ColdBox applications? — Full MVC subapplication — Automatic WireBox mapping — Automatic Interceptors — Overridable settings

Slide 27

Slide 27 text

Introducing ModuleConfig.cfc

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Bonus: ModuleConfig is also an Interceptor

Slide 31

Slide 31 text

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 = "*" ); } }

Slide 32

Slide 32 text

To get started automatically just box install cors !

Slide 33

Slide 33 text

Example Module redirectBack

Slide 34

Slide 34 text

redirectBack Directory Structure

Slide 35

Slide 35 text

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" ] }

Slide 36

Slide 36 text

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";

Slide 37

Slide 37 text

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 = {} }]; }

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

redirectBack Review

Slide 41

Slide 41 text

Leveraging WireBox

Slide 42

Slide 42 text

Leveraging WireBox this.autoMapModels = true; Automatically maps all of your models to {modelName}@{moduleName}. property name="builder" inject="Builder@qb";

Slide 43

Slide 43 text

Leveraging WireBox Use the full power of WireBox function configure() { binder.map( "DefaultGrammar" ) .to( "#moduleMapping#.models.grammars.MySQLGrammar" ); }

Slide 44

Slide 44 text

Modules, Modules, Everywhere You don't have to be on ForgeBox to be a module.

Slide 45

Slide 45 text

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).

Slide 46

Slide 46 text

UnderscoreCF

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

ForgeBox CFML's NPM

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

Private Packages Coming Soon — Storage on S3 — Semantic Versioning — Collaborators

Slide 53

Slide 53 text

Testing

Slide 54

Slide 54 text

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 ] ); } ); } ); } }

Slide 55

Slide 55 text

Run your tests on all CF engines at once!

Slide 56

Slide 56 text

TravisCI Integration language: java sudo: required jdk: - oraclejdk8 cache: directories: - $HOME/.CommandBox env: matrix: - [email protected] - 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

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

Scaffolding Modules

Slide 59

Slide 59 text

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....

Slide 60

Slide 60 text

Is there an easier way?

Slide 61

Slide 61 text

For ColdBox applications this is easy: box coldbox create app

Slide 62

Slide 62 text

Now it is that easy for your modules: box install cb-module-template box module scaffold my-awesome-module "It will blow your mind!"

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

What this does for you: — Create box.json — Create ModuleConfig.cfc — Scaffold tests folder — specs folder — runner.cfm — tests/Application.cfc

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

Aside: The repo itself is a great example of an advanced module

Slide 67

Slide 67 text

Bonus: Integration Testing your Module with ColdBox (See cborm-versioning for an example.)

Slide 68

Slide 68 text

So what are you waiting for?!?

Slide 69

Slide 69 text

Go make something awesome! !

Slide 70

Slide 70 text

Then share it with all of us. !

Slide 71

Slide 71 text

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