$30 off During Our Annual Pro Sale. View Details »

Accelerating Titanium Development with CoffeeScript, Compass, and Sass

Accelerating Titanium Development with CoffeeScript, Compass, and Sass

Wynn Netherland

September 20, 2011
Tweet

More Decks by Wynn Netherland

Other Decks in Programming

Transcript

  1. TITANIUM DEVELOPMENT WITH
    COFFEESCRIPT, COMPASS, AND SASS
    Accelerated
    WYNNNETHERLAND

    View Slide

  2. $ whoami

    View Slide

  3. NETHERLAND

    View Slide

  4. View Slide

  5. Mobile?
    Web?
    Both?

    View Slide

  6. Nice to meet ya.

    View Slide

  7. PIXELS I'VE PUSHED
    With some very talented folks.

    View Slide

  8. View Slide

  9. View Slide

  10. Play golf?
    Find this dude and
    get in on the beta.!

    View Slide

  11. View Slide

  12. View Slide

  13. View Slide

  14. Titanium powered kiosk!

    View Slide

  15. View Slide

  16. View Slide

  17. TITANIUM STACK
    A polyglot's

    View Slide

  18. COFFEESCRIPT

    View Slide

  19. It's still just JavaScript.

    View Slide

  20. var foo = function () {
    }
    foo = () ->
    I’d rather write this.
    JAVASCRIPT COFFEESCRIPT

    View Slide

  21. var button = Titanium.UI.createButton({
    title: 'I am a Button',
    height: 40,
    width: 200,
    top: 10
    });
    button.addEventListener('click', function(e) {
    alert("Oooh, that tickles!");
    });
    JAVASCRIPT

    View Slide

  22. button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    button.addEventListener 'click', (e) ->
    alert "Oooh, that tickles!"
    COFFEESCRIPT

    View Slide

  23. It's about more than aesthetics
    ;{ }
    For me,

    View Slide

  24. Some of my favorite features...

    View Slide

  25. for own key, value of query
    uri += "#{ key }=#{ escape(value) }&"
    COFFEESCRIPT
    var key, value;
    var __hasProp = Object.prototype.hasOwnProperty;
    for (key in query) {
    if (!__hasProp.call(query, key)) continue;
    value = query[key];
    uri += "" + key + "=" + (escape(value)) + "&";
    }
    JAVASCRIPT

    View Slide

  26. for own key, value of query
    uri += "#{ key }=#{ escape(value) }&"
    COFFEESCRIPT
    Comprehensions

    View Slide

  27. for own key, value of query
    uri += "#{ key }=#{ escape(value) }&"
    COFFEESCRIPT
    Interpolation

    View Slide

  28. courseButtonSubhead = Ti.UI.createLabel
    className: 'optRowSubhead'
    text: "#{GolfStatus.App.currentGame?.green?.name}"
    COFFEESCRIPT
    The Existential Operator

    View Slide

  29. class GolfStatus.Models.Game
    constructor: (@owner,
    @course,
    @playingFor='brag',
    @scoringFormat='low_net') ->
    @players = {}
    @addPlayer @owner if @owner
    @green = @course.greens[0] if @course
    @currentHole = 1
    @maxHolePlayed = 1
    # elsewhere
    game = new GolfStatus.Models.Game(...)
    COFFEESCRIPT
    Simple inheritance pattern

    View Slide

  30. class GolfStatus.Models.Game
    constructor: (@owner,
    @course,
    @playingFor='brag',
    @scoringFormat='low_net') ->
    @players = {}
    @addPlayer @owner if @owner
    @green = @course.greens[0] if @course
    @currentHole = 1
    @maxHolePlayed = 1
    COFFEESCRIPT
    @

    View Slide

  31. class GolfStatus.Models.Game
    constructor: (@owner,
    @course,
    @playingFor='brag',
    @scoringFormat='low_net') ->
    @players = {}
    @addPlayer @owner if @owner
    @green = @course.greens[0] if @course
    @currentHole = 1
    @maxHolePlayed = 1
    COFFEESCRIPT
    Default values

    View Slide

  32. class GolfStatus.Models.Game
    constructor: (@owner,
    @course,
    @playingFor='brag',
    @scoringFormat='low_net') ->
    @players = {}
    @addPlayer @owner if @owner
    @green = @course.greens[0] if @course
    @currentHole = 1
    @maxHolePlayed = 1
    COFFEESCRIPT
    More human conditionals

    View Slide

  33. GolfStatus.Models.Game::PlayingForTypes =
    brag: 'Bragging Rights'
    cash: 'Status Cash'
    GolfStatus.Models.Game::ScoringFormats =
    low_net: 'Low Net'
    low_grows: 'Low Gross'
    COFFEESCRIPT
    Easy object.prototype

    View Slide

  34. noticeHTML ='''



    '''
    noticeHTML += "#{noticeText}"
    noticeHTML += '''


    '''
    COFFEESCRIPT
    Heredocs

    View Slide

  35. Because string building sucks.

    View Slide

  36. And so much more.

    View Slide

  37. http://wynn.fm/2Y

    View Slide

  38. GET
    THE
    BOOK.
    http://wynn.fm/g8

    View Slide

  39. STYLESHEETS

    View Slide

  40. Are you using JSS?

    View Slide

  41. JSS works like CSS.

    View Slide

  42. Why do we have CSS?

    View Slide

  43. content
    presentation


    Wynn Netherland
    on design, development, and general geekery.


    Gowalla


    Facebook


    Dribbble


    LinkedIn


    GitHub


    Twitter

    ...
    ✂ You gotta keep 'em separated.

    View Slide

  44. A example

    View Slide

  45. var buttonOne = Titanium.UI.createButton({
    title:'I am a Button',
    height:40,
    width:200,
    top:10
    });
    var buttonTwo = Titanium.UI.createButton({
    title:'I am also a Button',
    image:'../images/chat.png',
    width:200,
    height:40,
    top:60
    });
    JAVASCRIPT

    View Slide

  46. var buttonOne = Titanium.UI.createButton({
    title:'I am a Button',
    height:40,
    width:200,
    top:10
    });
    var buttonTwo = Titanium.UI.createButton({
    title:'I am also a Button',
    image:'../images/chat.png',
    width:200,
    height:40,
    top:60
    });
    Presentation
    JAVASCRIPT

    View Slide

  47. #buttonOne {
    title:'I am a Button';
    width:200;
    height:40;
    top:10
    }
    #buttonTwo {
    title:'I am also a Button';
    image:'../images/chat.png';
    width:200;
    height:40;
    top:60
    }
    .button {
    height: 40;
    width: 200;
    }
    var buttonOne = Titanium.UI.createButton({
    id: "buttonOne",
    className: "button"
    });
    var buttonTwo = Titanium.UI.createButton({
    id: "buttonTwo",
    className: "button"
    });
    Behavior and composition in
    Presentation in
    .js
    .jss
    JSS
    JAVASCRIPT

    View Slide

  48. #buttonOne {
    title:'I am a Button';
    width:200;
    height:40;
    top:10
    }
    #buttonTwo {
    title:'I am also a Button';
    image:'../images/chat.png';
    width:200;
    height:40;
    top:60
    }
    .button {
    height: 40;
    width: 200;
    }
    var buttonOne = Titanium.UI.createButton({
    id: "buttonOne",
    className: "button"
    });
    var buttonTwo = Titanium.UI.createButton({
    id: "buttonTwo",
    className: "button"
    });
    Style hooks
    JAVASCRIPT
    JSS

    View Slide

  49. There's a better way to write CSS.
    JSS

    View Slide

  50. &
    CSS extensions &
    compiler
    Patterns &
    plugins

    View Slide

  51. gem install compass

    View Slide

  52. #buttonOne {
    title: 'I am a Button';
    width: 200;
    height: 40;
    top: 10
    }
    #buttonTwo {
    title: 'I am also a Button';
    image: '../images/chat.png';
    width: 200;
    height: 40;
    top: 60
    }
    .button {
    height: 40;
    width: 200;
    }
    Is it JSS or Sassy CSS?
    Yes?
    JSS / SCSS

    View Slide

  53. #buttonOne
    title: 'I am a Button'
    width: 200
    height: 40
    top: 10
    #buttonTwo
    title: 'I am also a Button'
    image: '../images/chat.png'
    width: 200
    height: 40
    top: 60
    .button
    height: 40
    width: 200
    I prefer Sass' original indented, whitespace aware syntax.
    SASS

    View Slide

  54. Which do you prefer?

    View Slide

  55. #buttonOne {
    title: 'I am a Button';
    width: 200;
    height: 40;
    top: 10
    }
    #buttonTwo {
    title: 'I am also a Button';
    image: '../images/chat.png';
    width: 200;
    height: 40;
    top: 60
    }
    .button {
    height: 40;
    width: 200;
    }
    SCSS

    View Slide

  56. #buttonOne
    title: 'I am a Button'
    width: 200
    height: 40
    top: 10
    #buttonTwo
    title: 'I am also a Button'
    image: '../images/chat.png'
    width: 200
    height: 40
    top: 60
    .button
    height: 40
    width: 200
    SASS

    View Slide

  57. Pick one. Or not. Mix and match.

    View Slide

  58. Organize with partials.

    View Slide

  59. stylesheets
    ├── _activity.sass
    ├── _base.sass
    ├── _confirmation.sass
    ├── _course.scss
    ├── _courses.sass
    ├── _friends.scss
    ├── _gameplay.sass
    ├── _leaderboard.sass
    ├── _leaders.sass
    ├── _login.sass
    ├── _requests.sass
    ├── _tourcard.sass
    └── app.sass
    @import 'base'
    @import 'login'
    @import 'activity'
    @import 'course'
    @import 'courses'
    @import 'friends'
    @import 'leaderboard'
    @import 'leaders'
    @import 'requests'
    @import 'tourcard'
    @import 'confirmation'
    @import 'gameplay'
    Resources
    ├── app.js
    ├── app.jss
    ...

    View Slide

  60. stylesheets
    ├── _activity.sass
    ├── _base.sass
    ├── _confirmation.sass
    ├── _course.scss
    ├── _courses.sass
    ├── _friends.scss
    ├── _gameplay.sass
    ├── _leaderboard.sass
    ├── _leaders.sass
    ├── _login.sass
    ├── _requests.sass
    ├── _tourcard.sass
    └── app.sass
    @import 'base'
    @import 'login'
    @import 'activity'
    @import 'course'
    @import 'courses'
    @import 'friends'
    @import 'leaderboard'
    @import 'leaders'
    @import 'requests'
    @import 'tourcard'
    @import 'confirmation'
    @import 'gameplay'
    Resources
    ├── app.js
    ├── app.jss
    ...
    Mix scss with sass
    if you're so inclined.

    View Slide

  61. Don't Repeat Yourself

    View Slide

  62. .user-info
    bottom: 1
    color: #333
    font-size: 11
    font-weight: bold
    height: auto
    left: 0
    shadowColor: #fff
    shadowOffset-x: 0
    shadowOffset-y: -1
    text-align: center
    width: 92
    SASS

    View Slide

  63. .user-info
    bottom: 1
    color: #333
    font:
    size: 11
    weight: bold
    height: auto
    left: 0
    shadowColor: #fff
    shadowOffset:
    x: 0
    y: '-1'
    text-align: center
    width: 92
    DRY it up. Nesting
    SASS

    View Slide

  64. #buttonOne
    title: 'I am a Button'
    width: 200
    height: 40
    top: 10
    #buttonTwo
    title: 'I am also a Button'
    image: '../images/chat.png'
    width: 200
    height: 40
    top: 60
    .button
    height: 40
    width: 200
    SASS

    View Slide

  65. =button
    height: 40
    width: 200
    #buttonOne
    +button
    title: 'I am a Button'
    top: 10
    #buttonTwo
    +button
    title: 'I am also a Button'
    image: '../images/chat.png'
    top: 60
    DRY it up. Mixins
    SASS

    View Slide

  66. =bottom-right($height: 40, $width: 200)
    height: $size
    width: $size
    right: 0
    bottom: 0
    #buttonOne
    +bottom-right
    title: 'I am a Button'
    #buttonTwo
    +bottom-right(50, 300)
    title: 'I am also a Button'
    image: '../images/chat.png'
    DRY it up. Mixins with params
    SASS

    View Slide

  67. #buttonOne
    title: 'I am a Button'
    width: 200
    height: 40
    top: 10
    #buttonTwo
    title: 'I am also a Button'
    image: '../images/chat.png'
    width: 200
    height: 40
    top: 60
    .button
    height: 40
    width: 200
    SASS

    View Slide

  68. .button
    height: 40
    width: 200
    #buttonOne
    @extend .button
    title: 'I am a Button'
    top: 10
    #buttonTwo
    @extend .button
    title: 'I am also a Button'
    image: '../images/chat.png'
    top: 60
    DRY it up. @extend
    SASS

    View Slide

  69. .button, #buttonOne, #buttonTwo {
    height: 40;
    width: 200;
    }
    #buttonOne {
    title: 'I am a Button';
    width: 200;
    }
    #buttonTwo {
    title: 'I am also a Button';
    image: '../images/chat.png';
    top: 60
    }
    DRY it up. @extend
    One less class in our .js
    JSS

    View Slide

  70. Craft themes with color functions.

    View Slide

  71. $button-base: #a7a7a7
    #buttonOne
    color: $button-base
    title: "Button 1"
    #buttonTwo
    color: $button-base
    title: "Button 2"
    variables
    SASS

    View Slide

  72. $button-base: #a7a7a7
    #buttonOne
    color: $button-base
    title: "Button 1"
    #buttonTwo
    color: $button-base
    title: "Button 2"
    variables
    SASS

    View Slide

  73. $button-base: #a7a7a7
    #buttonOne
    color: $button-base
    title: "Button 1"
    #buttonTwo
    color: darken($button-base, 20%)
    title: "Button 2"
    color functions
    SASS

    View Slide

  74. $button-base: #a7a7a7
    #buttonOne
    color: $button-base
    title: "Button 1"
    #buttonTwo
    color: darken($button-base, 20%)
    title: "Button 2"
    color functions
    SASS

    View Slide

  75. hue(#cc3) # => 60deg
    saturation(#cc3) # => 60%
    lightness(#cc3) # => 50%
    adjust-hue(#cc3, 20deg) # => #9c3
    saturate(#cc3, 10%) # => #d9d926
    desaturate(#cc3, 10%) # => #bfbf40
    lighten(#cc3, 10%) # => #d6d65c
    darken(#cc3, 10%) # => #a3a329
    grayscale(#cc3) # => desaturate(#cc3, 100%) = #808080
    complement(#cc3) # => adjust-hue(#cc3, 180deg) = #33c
    mix(#cc3, #00f) # => #e56619
    mix(#cc3, #00f, 10%) # => #f91405
    mix(#cc3, #00f, 90%) # => #d1b72d
    more color functions
    SASS

    View Slide

  76. mix(rgba(51, 255, 51, 0.75), #f00) # => rgba(178, 95, 19, 0.875)
    mix(rgba(51, 255, 51, 0.90), #f00) # => rgba(163, 114, 22, 0.95)
    alpha(rgba(51, 255, 51, 0.75)) # => 0.75
    opacity(rgba(51, 255, 51, 0.75)) # => 0.75
    opacify(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.85)
    fade-in(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.85)
    transparentize(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.65)
    fade-out(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.65)
    even more color functions
    SASS
    with alpha support!

    View Slide

  77. Building a hybrid native+web app?

    View Slide

  78. Share your stylesheet variables!

    View Slide

  79. No more vendor namespaces.
    Selector inheritance.
    URL helpers.
    So much more.

    View Slide

  80. I could write a book.

    View Slide

  81. Oh wait. We did!

    View Slide

  82. Isn’t she Sassy, folks?
    GET
    THE
    BOOK.
    http://wynn.fm/ti-sass

    View Slide

  83. sass40
    Save 40% and get early access!
    Sadly, sass100 is not a valid code.
    http://wynn.fm/ti-sass

    View Slide

  84. View Slide

  85. Patterns

    View Slide

  86. Web languages. Native apps.

    View Slide

  87. Stateful.

    View Slide

  88. Event driven.

    View Slide

  89. MVC?

    View Slide

  90. Views...

    View Slide

  91. ... are really ViewControllers.

    View Slide

  92. So we create View factories...

    View Slide

  93. ... and Model factories ...

    View Slide

  94. ...and factories that make miniature
    models of factories.

    View Slide

  95. The Titanium WayTM

    View Slide

  96. button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    button.addEventListener 'click', (e) ->
    alert "Oooh, that tickles!"
    COFFEESCRIPT
    Look familiar?

    View Slide

  97. So how do you manufacture your own views?

    View Slide

  98. Compose from other views.

    View Slide

  99. MyApp.Views.createLoginWindow = (opts={}) ->
    window = Ti.UI.createWindow(opts)
    button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    window.add button
    # methods
    say = (msg) ->
    alert(msg)
    # event handlers
    button.addEventListener 'click', -> say('hello')
    window
    COFFEESCRIPT

    View Slide

  100. MyApp.Views.createLoginWindow = (opts={}) ->
    window = Ti.UI.createWindow(opts)
    button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    window.add button
    # methods
    say = (msg) ->
    alert(msg)
    # event handlers
    button.addEventListener 'click', -> say('hello')
    window
    Create the factory method in
    the appropriate namespace.
    COFFEESCRIPT

    View Slide

  101. MyApp.Views.createLoginWindow = (opts={}) ->
    window = Ti.UI.createWindow(opts)
    button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    window.add button
    # methods
    say = (msg) ->
    alert(msg)
    # event handlers
    button.addEventListener 'click', -> say('hello')
    window
    Compose the view from
    Titanium types or others of
    your own
    COFFEESCRIPT

    View Slide

  102. MyApp.Views.createLoginWindow = (opts={}) ->
    window = Ti.UI.createWindow(opts)
    button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    window.add button
    # methods
    say = (msg) ->
    alert(msg)
    # event handlers
    button.addEventListener 'click', -> say('hello')
    window
    Methods in familiar place
    COFFEESCRIPT

    View Slide

  103. MyApp.Views.createLoginWindow = (opts={}) ->
    window = Ti.UI.createWindow(opts)
    button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    window.add button
    # methods
    say = (msg) ->
    alert(msg)
    # event handlers
    button.addEventListener 'click', -> say('hello')
    window
    And event handlers...
    COFFEESCRIPT

    View Slide

  104. MyApp.Views.createLoginWindow = (opts={}) ->
    window = Ti.UI.createWindow(opts)
    button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    window.add button
    # methods
    say = (msg) ->
    alert(msg)
    # event handlers
    button.addEventListener 'click', -> say('hello')
    window
    Return your view
    COFFEESCRIPT

    View Slide

  105. Models

    View Slide

  106. CoffeeScript classes

    View Slide

  107. class GolfStatus.Models.Game
    constructor: (@owner,
    @course,
    @playingFor='brag',
    @scoringFormat='low_net') ->
    serialize: ->
    deserialize: (data) ->
    save: ->
    resume: ->
    dataForSubmit: () ->
    submit: (error) ->
    ...
    COFFEESCRIPT

    View Slide

  108. API Wrappers

    View Slide

  109. class GolfStatus.API
    # Initialize with login and password
    constructor: (@login, @password) ->
    COFFEESCRIPT
    CoffeeScript class

    View Slide

  110. ...
    # Build the full API URI for a request
    requestURI: (path, query={}) ->
    uri = "#{GolfStatus.API_ENDPOINT}#{path}.json?"
    for own key, value of query
    uri += "#{ key }=#{ escape(value) }&"
    uri
    COFFEESCRIPT
    URI building

    View Slide

  111. # Common request handling across all verbs
    request: (path, options, authenticated=true) ->
    # Default to GET
    options.method ?= 'GET'
    options.query ?= {}
    options.success ?= -> Ti.API.info
    options.error ?= -> Ti.API.error
    xhr = Ti.Network.createHTTPClient()
    xhr.onreadystatechange = (e) ->
    ...
    # Default event handlers
    # Basic auth
    # other common stuff
    ...
    if options.body
    data = JSON.stringify(options.body)
    Ti.API.debug data
    xhr.send(data)
    else
    xhr.send()
    COFFEESCRIPT
    HTTP Request building

    View Slide

  112. # High level method for GET requests
    get: (path, options, authenticated=true) ->
    options.method = 'GET'
    @request path, options, authenticated
    # High level method for POST requests
    post: (path, options, authenticated=true) ->
    options.method = 'POST'
    @request path, options, authenticated
    # High level method for DELETE requests
    delete: (path, options, authenticated=true) ->
    options.method = 'DELETE'
    @request path, options, authenticated
    COFFEESCRIPT
    High level methods for HTTP verbs

    View Slide

  113. # ### Authenticate the user ###
    authenticate: (options) ->
    Ti.API.debug "GolfStatus.API.authenticate"
    @get '/me', options
    # ### Logout the user ###
    logout: (options) ->
    Ti.API.debug "GolfStatus.API.logout"
    @delete '/logout', options
    # ### Forgot password
    forgotPassword: (email, options) ->
    Ti.API.debug "GolfStatus.API.forgotPassword"
    options.query = {}
    options.query.email = email
    @post '/passwords', options, false
    # ### Convenience method to get current user info ###
    me: (options) ->
    Ti.API.debug "GolfStatus.API.me"
    @authenticate options
    COFFEESCRIPT
    Higher level API methods

    View Slide

  114. Folder structure

    View Slide

  115. .
    ├── Resources # Titanium root
    │ └── vendor # JavaScript frameworks
    ├── src # CoffeeScript root
    │ └── golf_status # App root
    │ ├── models
    │ └── views
    │ ├── account # App domains
    │ ├── activity
    │ ├── courses
    │ ├── leaderboard
    │ └── play
    └── stylesheets # Sass

    View Slide

  116. Stitching it all together

    View Slide

  117. app.js

    View Slide

  118. GolfStatus =
    Models: {}
    Views:
    Account: {}
    Activity: {}
    Courses: {}
    Leaderboard: {}
    Play: {}
    Ti.include('vendor/date.js')
    Ti.include('vendor/underscore.js')
    Ti.include('golf_status.js')
    GolfStatus.App.init()
    COFFEESCRIPT

    View Slide

  119. GolfStatus =
    Models: {}
    Views:
    Account: {}
    Activity: {}
    Courses: {}
    Leaderboard: {}
    Play: {}
    Ti.include('vendor/date.js')
    Ti.include('vendor/underscore.js')
    Ti.include('golf_status.js')
    GolfStatus.App.init()
    COFFEESCRIPT
    Set up your namespaces

    View Slide

  120. GolfStatus =
    Models: {}
    Views:
    Account: {}
    Activity: {}
    Courses: {}
    Leaderboard: {}
    Play: {}
    Ti.include('vendor/date.js')
    Ti.include('vendor/underscore.js')
    Ti.include('golf_status.js')
    GolfStatus.App.init()
    COFFEESCRIPT
    third party frameworks

    View Slide

  121. GolfStatus =
    Models: {}
    Views:
    Account: {}
    Activity: {}
    Courses: {}
    Leaderboard: {}
    Play: {}
    Ti.include('vendor/date.js')
    Ti.include('vendor/underscore.js')
    Ti.include('golf_status.js')
    GolfStatus.App.init()
    COFFEESCRIPT
    All of our app in just one file

    View Slide

  122. GolfStatus =
    Models: {}
    Views:
    Account: {}
    Activity: {}
    Courses: {}
    Leaderboard: {}
    Play: {}
    Ti.include('vendor/date.js')
    Ti.include('vendor/underscore.js')
    Ti.include('golf_status.js')
    GolfStatus.App.init()
    COFFEESCRIPT
    Fire up the app and first window

    View Slide

  123. Lean app.js makes for flexibility

    View Slide

  124. Tapping through to test deep screens bites!

    View Slide

  125. # GolfStatus.App.init()
    window = GolfStatus.Views.Play.createGameWindow()
    window.open()
    COFFEESCRIPT
    Comment out init and
    fire up the deepest view.

    View Slide

  126. make

    View Slide

  127. run-iphone:
    & @DEVICE_TYPE=iphone make run
    test-iphone:
    & @DEVICE_TYPE=iphone make test
    run-ipad:
    & @DEVICE_TYPE=ipad make run
    test-ipad:
    & @DEVICE_TYPE=ipad make test
    run:
    & @if [ "${DEVICE_TYPE}" == "" ]; then\
    & & echo "Please run \"make run-[iphone|ipad]\" instead.";\
    & & exit 1;\
    & fi
    & @mkdir -p ${PROJECT_ROOT}/${PROJECT_NAME}/Resources/test/
    & @echo "" > ${PROJECT_ROOT}/${PROJECT_NAME}/Resources/test/enabled.js
    & @make launch-titanium
    http://wynn.fm/g9
    guilhermechapiewski (Guilherme Chapiewski)

    View Slide

  128. rake
    I'm a Rubyist, so I speak

    View Slide

  129. Compile

    View Slide

  130. def compile_sass
    puts "Compiling stylesheets".blue
    input = "stylesheets/app.sass"
    output = "Resources/app.jss"
    system "sass --compass -C -t expanded #{input} > #{output}"
    end
    RAKEFILE

    View Slide

  131. def compile_coffee
    paths = `find src/golf_status -name '*.coffee'`.split("\n")
    compilation = (
    puts "Compiling CoffeeScript (golf_status.js)".blue
    output = "Resources/golf_status.js"
    system "coffee --join #{output} -b -c #{paths.join(' ')}" and
    puts "Compiling CoffeeScript (app.js)".blue
    system "coffee -p --bare src/app.coffee > Resources/app.js"
    )
    if compilation
    puts "Successfully compiled CoffeeScript".green
    else
    puts "Error compiling CoffeeScript".red
    end
    compilation
    end
    RAKEFILE

    View Slide

  132. def compile_coffee
    paths = `find src/golf_status -name '*.coffee'`.split("\n")
    compilation = (
    puts "Compiling CoffeeScript (golf_status.js)".blue
    output = "Resources/golf_status.js"
    system "coffee --join #{output} -b -c #{paths.join(' ')}"
    puts "Compiling CoffeeScript (app.js)".blue
    system "coffee -p --bare src/app.coffee > Resources/app.js"
    )
    if compilation
    puts "Successfully compiled CoffeeScript".green
    else
    puts "Error compiling CoffeeScript".red
    end
    compilation
    end
    RAKEFILE Compile App namespaces to single file

    View Slide

  133. def compile_coffee
    paths = `find src/golf_status -name '*.coffee'`.split("\n")
    compilation = (
    puts "Compiling CoffeeScript (golf_status.js)".blue
    output = "Resources/golf_status.js"
    system "coffee --join #{output} -b -c #{paths.join(' ')}"
    puts "Compiling CoffeeScript (app.js)".blue
    system "coffee -p --bare src/app.coffee > Resources/app.js"
    )
    if compilation
    puts "Successfully compiled CoffeeScript".green
    else
    puts "Error compiling CoffeeScript".red
    end
    compilation
    end
    RAKEFILE Compile app.js which includes the app library

    View Slide

  134. Build

    View Slide

  135. def build(options={})
    return unless compile
    options[:device] ||= 'iphone'
    puts "Building with Titanium...
    (DEVICE_TYPE:#{options[:device]})".blue
    sh %Q{bash -c "#{TI_BUILD} run #{PROJECT_ROOT}/ #{IPHONE_SDK_VERSION}
    #{APP_ID} #{APP_NAME} #{APP_DEVICE}" \
    | perl -pe 's/^\\[DEBUG\\].*$/\\e[35m$&\\e[0m/g;s/^\\[INFO\\].*$/\\e[36m
    $&\\e[0m/g;s/^\\[WARN\\].*$/\\e[33m$&\\e[0m/g;s/^\\[ERROR\\].*$/\\e[31m
    $&\\e[0m/g;'}
    end
    RAKEFILE

    View Slide

  136. def build(options={})
    return unless compile
    options[:device] ||= 'iphone'
    puts "Building with Titanium...
    (DEVICE_TYPE:#{options[:device]})".blue
    sh %Q{bash -c "#{TI_BUILD} run #{PROJECT_ROOT}/ #{IPHONE_SDK_VERSION}
    #{APP_ID} #{APP_NAME} #{APP_DEVICE}" \
    | perl -pe 's/^\\[DEBUG\\].*$/\\e[35m$&\\e[0m/g;s/^\\[INFO\\].*$/\\e[36m
    $&\\e[0m/g;s/^\\[WARN\\].*$/\\e[33m$&\\e[0m/g;s/^\\[ERROR\\].*$/\\e[31m
    $&\\e[0m/g;'}
    end
    RAKEFILE Build with Titanium Python command line

    View Slide

  137. def build(options={})
    return unless compile
    options[:device] ||= 'iphone'
    puts "Building with Titanium...
    (DEVICE_TYPE:#{options[:device]})".blue
    sh %Q{bash -c "#{TI_BUILD} run #{PROJECT_ROOT}/ #{IPHONE_SDK_VERSION}
    #{APP_ID} #{APP_NAME} #{APP_DEVICE}" \
    | perl -pe 's/^\\[DEBUG\\].*$/\\e[35m$&\\e[0m/g;s/^\\[INFO\\].*$/\\e[36m
    $&\\e[0m/g;s/^\\[WARN\\].*$/\\e[33m$&\\e[0m/g;s/^\\[ERROR\\].*$/\\e[31m
    $&\\e[0m/g;'}
    end
    RAKEFILE
    Pipe to PERL for some colored terminal goodness

    View Slide

  138. View Slide

  139. Choose what works for you.

    View Slide

  140. JavaScript Frameworks

    View Slide

  141. Underscore.js
    https://github.com/documentcloud/underscore
    From Jeremy Ashkenas,
    the creator of CoffeeScript.

    View Slide

  142. Don't Repeat Yourself Not Repeating Yourself

    View Slide

  143. Ti GEM
    Automating these patterns. A work in progress.

    View Slide

  144. gem install ti

    View Slide

  145. Generate.

    View Slide

  146. ti new

    View Slide

  147. ti new codestrong-app com.codestrong.app iphone

    View Slide

  148. ├── Coffeefile
    ├── Guardfile
    ├── LICENSE
    ├── Rakefile
    ├── Readme.mkd
    ├── Resources
    │ ├── app.js
    │ ├── app.jss
    │ ├── images
    │ │ ├── KS_nav_ui.png
    │ │ └── KS_nav_views.png
    │ ├── lsrc.js
    │ └── vendor
    ├── app
    │ ├── app.coffee
    │ └── lsrc
    │ ├── api.coffee
    │ ├── app.coffee
    │ ├── helpers
    │ │ └── application.coffee
    │ ├── models
    │ ├── stylesheets
    │ │ ├── app.sass
    │ │ └── partials
    │ └── views
    ├── build
    ├── config
    │ └── config.rb
    ├── docs
    ├── spec
    │ ├── app_spec.coffee
    │ ├── helpers
    │ ├── models
    │ └── views
    ├── tiapp.xml
    └── tmp

    View Slide

  149. ti generate

    View Slide

  150. Golf.Views.GamePlay.createScoreCardView = (options) ->
    view = Ti.UI.createView (options)
    view

    View Slide

  151. ti scaffold

    View Slide

  152. Compile.

    View Slide

  153. ti compile

    View Slide

  154. Build.

    View Slide

  155. ti build

    View Slide

  156. Ti GEM
    @revans @baldrailers
    @rupakg

    View Slide

  157. Get involved!

    View Slide

  158. We've got BIG ideas.

    View Slide

  159. Testing.

    View Slide

  160. Jasmine

    View Slide

  161. Jasmine
    https://github.com/akahigeg/jasmine-titanium

    View Slide

  162. XIB

    View Slide

  163. xib2js
    https://github.com/daoki2/xib2js

    View Slide

  164. js2coffee
    http://ricostacruz.com/js2coffee/

    View Slide

  165. http://spkr8.com/t/8342
    QUESTIONS?

    View Slide