Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass

  • 2,190 views
Uploaded on

JavaScript and Titanium's JavaScript Stylesheets would be the quickest way to develop native mobile applications if it weren't for CoffeeScript and Sass. This talk will show you how to speed up your …

JavaScript and Titanium's JavaScript Stylesheets would be the quickest way to develop native mobile applications if it weren't for CoffeeScript and Sass. This talk will show you how to speed up your dev cycles and use CoffeeScript and Sass not only to write code faster, but better organize your JavaScript and JSS.

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • This is a gold mine of tips. I am a Desktop MVC developer moving into the mobile realm. I knew in generic terms what I needed, but this talk in an apprenticeship in 40 minutes. It provided the specific detail I needed to go off on my own empowered to do serious mobile app development seriously. Must Watch.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
2,190
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
32
Comments
1
Likes
3

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. TITANIUM DEVELOPMENT WITHAccelerated COFFEESCRIPT, COMPASS, AND SASS WYNNNETHERLAND
  • 2. $ whoami
  • 3. NETHERLAND
  • 4. Mobile?Web?Both?
  • 5. Nice to meet ya.
  • 6. PIXELS IVE PUSHEDWith some very talented folks.
  • 7. Play golf?Find this dude andget in on the beta.!
  • 8. Titanium powered kiosk!
  • 9. A polyglotsTITANIUM STACK
  • 10. COFFEESCRIPT
  • 11. Its still just JavaScript.
  • 12. var foo = function () { foo = () -> }JAVASCRIPT COFFEESCRIPT I’d rather write this.
  • 13. 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
  • 14. button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 top: 10 button.addEventListener click, (e) -> alert "Oooh, that tickles!"COFFEESCRIPT
  • 15. For me,Its about more than aesthetics ; {}
  • 16. Some of my favorite features...
  • 17. 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
  • 18. Comprehensions for own key, value of query uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT
  • 19. Interpolation for own key, value of query uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT
  • 20. The Existential Operator courseButtonSubhead = Ti.UI.createLabel className: optRowSubhead text: "#{GolfStatus.App.currentGame?.green?.name}"COFFEESCRIPT
  • 21. Simple inheritance pattern 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
  • 22. @ 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 = 1COFFEESCRIPT
  • 23. Default values 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 = 1COFFEESCRIPT
  • 24. More human conditionals 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 = 1COFFEESCRIPT
  • 25. Easy object.prototype GolfStatus.Models.Game::PlayingForTypes = brag: Bragging Rights cash: Status Cash GolfStatus.Models.Game::ScoringFormats = low_net: Low Net low_grows: Low GrossCOFFEESCRIPT
  • 26. Heredocs noticeHTML = <html> <head></head> <body> noticeHTML += "<div>#{noticeText}</div>" noticeHTML += </body> </html> COFFEESCRIPT
  • 27. Because string building sucks.
  • 28. And so much more.
  • 29. http://wynn.fm/2Y
  • 30. GETTHEBOOK. http://wynn.fm/g8
  • 31. STYLESHEETS
  • 32. Are you using JSS?
  • 33. JSS works like CSS.
  • 34. Why do we have CSS?
  • 35. <ul class=wynning> <li class=logo-mark> <a href=/about>Wynn Netherland</a> on design, development, and general geekery. </li> <li> <a class=gowalla href=http://gowalla.com/pengwynn>Gowalla</a> </li> <li> <a class=facebook href=http://facebook.com/pengwynn>Facebook</a> content </li> <li> <a class=dribbble href=http://dribbble.com/pengwynn>Dribbble</a> </li> <li> <a class=linked-in href=http://linkedin.com/in/netherland>LinkedIn</a> </li> <li> <a class=github href=http://github.com/pengwynn>GitHub</a> </li> <li> <a class=twitter href=http://twitter.com/pengwynn>Twitter</a> </li>... You gotta keep em separated.✂ presentation
  • 36. A example
  • 37. 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
  • 38. var buttonOne = Titanium.UI.createButton({ title:I am a Button, height:40, width:200, Presentation top:10 }); var buttonTwo = Titanium.UI.createButton({ title:I am also a Button, image:../images/chat.png, width:200, height:40, top:60 });JAVASCRIPT
  • 39. var buttonOne = Titanium.UI.createButton({ id: "buttonOne", JAVASCRIPT Behavior and composition in className: "button"});var buttonTwo = Titanium.UI.createButton({ id: "buttonTwo", className: "button"}); .js#buttonOne { title:I am a Button; JSS width:200; height:40; top:10}#buttonTwo { Presentation in title:I am also a Button; image:../images/chat.png; width:200; height:40; .jss top:60}.button { height: 40; width: 200;}
  • 40. var buttonOne = Titanium.UI.createButton({ id: "buttonOne", JAVASCRIPT className: "button" Style hooks});var buttonTwo = Titanium.UI.createButton({ id: "buttonTwo", className: "button"});#buttonOne { title:I am a Button; JSS 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;}
  • 41. JSSTheres a better way to write CSS.
  • 42. Patte rns & io n s & plugins SS e xtensC co mpiler &
  • 43. gem install compass
  • 44. Is it JSS or Sassy CSS? #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; }JSS / SCSS Yes?
  • 45. I prefer Sass original indented, whitespace aware syntax. #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
  • 46. Which do you prefer?
  • 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; }SCSS
  • 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: 200SASS
  • 49. Pick one. Or not. Mix and match.
  • 50. Organize with partials.
  • 51. stylesheets├── _activity.sass├── _base.sass├── _confirmation.sass├── _course.scss├── _courses.sass├── _friends.scss├── _gameplay.sass├── _leaderboard.sass├── _leaders.sass├── _login.sass├── _requests.sass @import base├── _tourcard.sass @import login└── app.sass @import activity @import course @import courses @import friends @import leaderboard @import leaders @import requests @import tourcard @import confirmation @import gameplayResources├── app.js├── app.jss...
  • 52. stylesheets Mix scss with sass├── _activity.sass├── _base.sass├── _confirmation.sass if youre so inclined.├── _course.scss├── _courses.sass├── _friends.scss├── _gameplay.sass├── _leaderboard.sass├── _leaders.sass├── _login.sass├── _requests.sass @import base├── _tourcard.sass @import login└── app.sass @import activity @import course @import courses @import friends @import leaderboard @import leaders @import requests @import tourcard @import confirmation @import gameplayResources├── app.js├── app.jss...
  • 53. Dont Repeat Yourself
  • 54. .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: 92SASS
  • 55. DRY it up. Nesting .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: 92SASS
  • 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: 200SASS
  • 57. DRY it up. Mixins =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: 60SASS
  • 58. DRY it up. Mixins with params =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.pngSASS
  • 59. #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: 200SASS
  • 60. DRY it up. @extend .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: 60SASS
  • 61. DRY it up. @extend .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; One less class in our .js top: 60 }JSS
  • 62. Craft themes with color functions.
  • 63. variables $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: $button-base title: "Button 2"SASS
  • 64. variables $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: $button-base title: "Button 2"SASS
  • 65. color functions $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: darken($button-base, 20%) title: "Button 2"SASS
  • 66. color functions $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: darken($button-base, 20%) title: "Button 2"SASS
  • 67. more color functions 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%) # => #d1b72dSASS
  • 68. even more color functions 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 with alpha support! 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)SASS
  • 69. Building a hybrid native+web app?
  • 70. Share your stylesheet variables!
  • 71. No more vendor namespaces.Selector inheritance.URL helpers.So much more.
  • 72. I could write a book.
  • 73. Oh wait. We did!
  • 74. Isn’t she Sassy, folks?GETTHEBOOK. http://wynn.fm/ti-sass
  • 75. Save 40% and get early access! sass40Sadly, sass100 is not a valid code. http://wynn.fm/ti-sass
  • 76. Patterns
  • 77. Web languages. Native apps.
  • 78. Stateful.
  • 79. Event driven.
  • 80. MVC?
  • 81. Views...
  • 82. ... are really ViewControllers.
  • 83. So we create View factories...
  • 84. ... and Model factories ...
  • 85. ...and factories that make miniature models of factories.
  • 86. The Titanium WayTM
  • 87. button = Titanium.UI.createButton title: I am a Button height: 40 Look familiar? width: 200 top: 10 button.addEventListener click, (e) -> alert "Oooh, that tickles!"COFFEESCRIPT
  • 88. So how do you manufacture your own views?
  • 89. Compose from other views.
  • 90. 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) windowCOFFEESCRIPT
  • 91. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 Create the factory method in the appropriate namespace. top: 10 window.add button # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  • 92. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 Compose the view from top: 10 window.add button Titanium types or others of # methods your own say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  • 93. 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 in familiar place # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  • 94. 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 And event handlers... # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  • 95. 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 Return your view # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  • 96. Models
  • 97. CoffeeScript classes
  • 98. class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor=brag, @scoringFormat=low_net) -> serialize: -> deserialize: (data) -> save: -> resume: -> dataForSubmit: () -> submit: (error) -> ...COFFEESCRIPT
  • 99. API Wrappers
  • 100. CoffeeScript class class GolfStatus.API # Initialize with login and password constructor: (@login, @password) ->COFFEESCRIPT
  • 101. URI building ... # 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) }&" uriCOFFEESCRIPT
  • 102. HTTP Request building # 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
  • 103. High level methods for HTTP verbs # 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, authenticatedCOFFEESCRIPT
  • 104. Higher level API methods # ### 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 optionsCOFFEESCRIPT
  • 105. Folder structure
  • 106. .├── Resources # Titanium root│   └── vendor # JavaScript frameworks├── src # CoffeeScript root│   └── golf_status # App root│   ├── models│   └── views│   ├── account # App domains│   ├── activity│   ├── courses│   ├── leaderboard│   └── play└── stylesheets # Sass
  • 107. Stitching it all together
  • 108. app.js
  • 109. 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
  • 110. GolfStatus = Models: {} Views: Set up your namespaces Account: {} Activity: {} Courses: {} Leaderboard: {} Play: {} Ti.include(vendor/date.js) Ti.include(vendor/underscore.js) Ti.include(golf_status.js) GolfStatus.App.init()COFFEESCRIPT
  • 111. GolfStatus = Models: {} Views: Account: {} Activity: {} Courses: {} third party frameworks Leaderboard: {} Play: {} Ti.include(vendor/date.js) Ti.include(vendor/underscore.js) Ti.include(golf_status.js) GolfStatus.App.init()COFFEESCRIPT
  • 112. 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() All of our app in just one fileCOFFEESCRIPT
  • 113. 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() Fire up the app and first windowCOFFEESCRIPT
  • 114. Lean app.js makes for flexibility
  • 115. Tapping through to test deep screens bites!
  • 116. # GolfStatus.App.init() window = GolfStatus.Views.Play.createGameWindow() window.open() Comment out init and fire up the deepest view.COFFEESCRIPT
  • 117. make
  • 118. run-iphone:& @DEVICE_TYPE=iphone make runtest-iphone:& @DEVICE_TYPE=iphone make testrun-ipad:& @DEVICE_TYPE=ipad make runtest-ipad:& @DEVICE_TYPE=ipad make testrun:& @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 guilhermechapiewski (Guilherme Chapiewski) http://wynn.fm/g9
  • 119. Im a Rubyist, so I speak rake
  • 120. Compile
  • 121. def compile_sass puts "Compiling stylesheets".blue input = "stylesheets/app.sass" output = "Resources/app.jss" system "sass --compass -C -t expanded #{input} > #{output}" endRAKEFILE
  • 122. 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 endRAKEFILE
  • 123. 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 endRAKEFILE Compile App namespaces to single file
  • 124. 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 endRAKEFILE Compile app.js which includes the app library
  • 125. Build
  • 126. 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;} endRAKEFILE
  • 127. 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;} endRAKEFILE Build with Titanium Python command line
  • 128. 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 Pipe to PERL for some colored terminal goodnessRAKEFILE
  • 129. Choose what works for you.
  • 130. JavaScript Frameworks
  • 131. Underscore.jshttps://github.com/documentcloud/underscore From Jeremy Ashkenas, the creator of CoffeeScript.
  • 132. Dont Repeat Yourself Not Repeating Yourself
  • 133. Ti GEMAutomating these patterns. A work in progress.
  • 134. gem install ti
  • 135. Generate.
  • 136. ti new <name> <id> <platform>
  • 137. ti new codestrong-app com.codestrong.app iphone
  • 138. ├── 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
  • 139. ti generate <model/controller/view> <name>
  • 140. Golf.Views.GamePlay.createScoreCardView = (options) -> view = Ti.UI.createView (options) view
  • 141. ti scaffold <window/tabgroup/view> <domain> <name>
  • 142. Compile.
  • 143. ti compile <all/coffee/sass>
  • 144. Build.
  • 145. ti build <all/iphone/android/ipad/desktop/>
  • 146. Ti GEM@revans @baldrailers @rupakg
  • 147. Get involved!
  • 148. Weve got BIG ideas.
  • 149. Testing.
  • 150. Jasmine
  • 151. Jasminehttps://github.com/akahigeg/jasmine-titanium
  • 152. XIB
  • 153. xib2jshttps://github.com/daoki2/xib2js
  • 154. js2coffeehttp://ricostacruz.com/js2coffee/
  • 155. QUESTIONS?http://spkr8.com/t/8342