Scala and LiftWeb presentation (Russian)

32
Дмитрий Стропалов, Александр Михальчук +

Transcript of Scala and LiftWeb presentation (Russian)

Page 1: Scala and LiftWeb presentation (Russian)

Дмитрий Стропалов, Александр Михальчук

+

Page 2: Scala and LiftWeb presentation (Russian)

If I were to pick a language to use today other than Java, it would be Scala

James Gosling

I can honestly say if someone had shown me the Programming in Scala book by by Martin 

Odersky, Lex Spoon & Bill Venners back in 2003 I’d probably have never created Groovy

James Strachan

Page 3: Scala and LiftWeb presentation (Russian)

возникновение

• Разработан  в  2001­2004  годах  (представлен  в  2004    г.)  в Лаборатории  методов  программирования  EPFL (Федеральная  политехническая  школа  Лозанны, Швейцария) под руководством Мартина Одерски  (Martin Odersky) 

• Большое  влияние  оказали  исследовательские  работы  в области разработки (компонентного) ПО, ЯП

• Попытка  разработки  языка,  который  бы  хорошо масштабировался (SCAlable LAnguage)

• Унификация  объектно­ориентированного  и функционального подходов и предоставление их в языке со  статической  типизацией.  Расширенные  механизмы абстракции, композиции и декомпозиции

• Хорошая  интеграция  с  существующими  платформами  и библиотеками — изначальная ориентация на совместную работу с Java и .NET

Page 4: Scala and LiftWeb presentation (Russian)

«академический» язык

• LinkedIn  –  фреймфорк  “Norbert”  для  построения асинхронных,  кластерных,  высоконагруженных приложений. Представление социального графа                 

• EDF – крупнейшая во Франции энергетическая компания

• Twitter – главная очередь сообщений (message queue)

• Novell  –  сервис  “Vibe  Cloud”,  предоставляющий корпоративную  закрытую  и  защищенную  платформу  для совместной работы

• The  Guardian  –  API для  “Open  Platform”, предоставление доступа к медийному архиву агенства

• Xerox – различное ПО, включая и клиентское

• FourSquare – полностью все предоставляемые сервисы

• Sony – система управления хранением данных

• Siemes (+ SAP) – корпоративная система сообщений

• …  

Page 5: Scala and LiftWeb presentation (Russian)

основные концепции

• Бесшовная интеграция с Java­кодом (C#/.NET)

• Единообразная  объектная  модель  –  любое  значение является объектом, любая операция – вызов метода

• Функциональный язык – функции являются полноправными значениями. Каждая функция возвращает значение

• Механизмы абстракций как для типов, так и для значений

• Использование  «примесей»  (mixin,  trait)  для  композиции классов

• Сравнение с образцом (pattern matching)

• Естественная обработка документов XML

• Выведение типов

• Неизменяемые (immutable types) типы

• Ленивые (lazy) вычисления

Page 6: Scala and LiftWeb presentation (Russian)

hello world!

Вариант I:object Application {

     def main(args: Array[String]): Unit = {         for (arg <­ args) {          if (arg.startsWith("­"))             println(arg)         }     }

}

Page 7: Scala and LiftWeb presentation (Russian)

hello world!

Вариант I:object Application {

     def main(args: Array[String]): Unit = {         for (arg <­ args) {          if (arg.startsWith("­"))             println(arg)         }     }

}

Вариант II:     def main(args: Array[String]): Unit = {         for (arg <­ args; if arg.startsWith("­"))            println(arg)     }

Page 8: Scala and LiftWeb presentation (Russian)

hello world!

Вариант I:object Application {

     def main(args: Array[String]): Unit = {         for (arg <­ args) {          if (arg.startsWith("­"))             println(arg)         }     }

}

Вариант II:     def main(args: Array[String]): Unit = {         for (arg <­ args; if arg.startsWith("­"))            println(arg)     }

Вариант III:     def main(args: Array[String]): Unit = {

args.withFilter(_.startsWith("­")).map(println)     }

Page 9: Scala and LiftWeb presentation (Russian)

значения и переменные

   val a: Int = 5        val b = {            println("Init b")            10        }        var c = 15        lazy val d = {            println("Init d")            a + c        }

        println("a:%d b:%d c:%d".format(a, b, c))        c = 20        println("c:%d d:%d".format(c, d))        println("d:" + d)

>>>   Init b a:5 b:10 c:15 Init d c:20 d:25 d:25

Page 10: Scala and LiftWeb presentation (Russian)

классы и объекты

class Parent(value: String) {     val classValue = value

}

class A1 {     val a: Int = 0     private var b = 0     def getB = b

}

object A1 extends Parent("Object A1: ") {     def setA(obj: A1) { obj.b = 5 }

}

object Application extends Application {     val obj = new A1     A1.setA(obj)     println(A1.classValue + obj.getB)

}         >>>  Object A1: 5

 

Page 11: Scala and LiftWeb presentation (Russian)

трейты (traits)

trait Role {     def getRole: Int     def isAdmin = if (getRole == 0) true else false

}

trait Info {     def getInfo: String     def setInfo(info: String)

}

class User(role: Int) extends Role with Info {     val userRole = role     var userInfo: String = ""     def getRole = userRole     def getInfo = userInfo     def setInfo(info: String) { 

userInfo = info }

}  

Page 12: Scala and LiftWeb presentation (Russian)

анонимные функции

object Application extends Application {     val hello = () => "Hello, anonymous"     val foo = (x: String) => x.split(':').mkString(", ")     def bar(s: String, f: String => String) = {         f(s)     }

     println(hello)println(hello())

     println(foo("value1:value2:value3:value4"))     println(bar("John:Mike:Ann", foo))

}

>>>  <function0>Hello, anonymousvalue1, value2, value3, value4John, Mike, Ann 

Page 13: Scala and LiftWeb presentation (Russian)

карринг

def filter(xs: List[Int], p: Int => Boolean): List[Int] =if (xs.isEmpty) Nilelse if (p(xs.head)) xs.head :: filter(xs.tail, p)else filter(xs.tail, p)

def modN(n: Int)(x: Int) = ((x % n) == 0)

val list = (1 to 10).toListprintln(filter(list, modN(2)))println(filter(list, modN(3))) 

        

>>>  List(2, 4, 6, 8, 10)List(3, 6, 9) 

Page 14: Scala and LiftWeb presentation (Russian)

xml

val xml =     <depot>         <item name="item 1">             <part name="part 1"/>             <part name="part 2"/>             <item>inner item</item>         </item>         <item name="item 2"></item>         <label type="title">Depot title</label>     </depot>         

xml \ "item"     xml \\ "item"     xml \\ "@type"

 

Page 15: Scala and LiftWeb presentation (Russian)

xml

val ptype = "box"     val title = "Examples"     val item = <item type={ ptype }>{ title }</item>

     val items =         <items>             {for (index <­ (0 to 3).toList)                 yield <item>{ index }</item>}         </items>

     println(item)     println(items)

>>> <item type="box">Examples</item><items>

        <item>0</item><item>1</item><item>2</item><item>3</item>

       </items>

Page 16: Scala and LiftWeb presentation (Russian)

сравнение с образцом

def matcher(x: Any) = {         x match {            case 1 => println("Integer value 1")            case y: Int => println("Integer value: " + y)            case <e>{ tagValue }</e> => 

println("XML Tag value: " + tagValue)            case _ => println("Something else: " + x)         }     }

     matcher(1)     matcher(10)     matcher(<e>Lorem ipsum</e>)     matcher("simple string")

>>> Integer value 1Integer value: 10XML Tag value: Lorem ipsumSomething else: simple string

Page 17: Scala and LiftWeb presentation (Russian)

магический implicit

implicit def double2int(x: Double) = {        println("converting double to int ...")         if (x < 10) 0 else x.toInt     }     val i: Int = 3.5     println(i)

>>> converting double to int ...0

implicit val a: Int = 10     implicit val b: Double = 1.5     def foo(implicit a: Int, b: Double) = {

println("%d, %f".format(a, b))}

     foo

>>> 10, 1.500000

Page 18: Scala and LiftWeb presentation (Russian)

The first rule of Lift is:                                              It's easier than you think.

I think the most important feature we have in Lift is the community around it

(committers and non­committers). I have joined the mailing list just a few months

ago and I am impressed with how willing everyone is to help each other.

Page 19: Scala and LiftWeb presentation (Russian)

общая информация

• Разработка  начата  в  2007  году,  сейчас  достигнута версия 2.2. Главный разработчик — Девид Поллак (David Pollak). Рабочее название было “Scala on Sails” 

• Разрабатывается  с  целью  объединить  лучшие  идеи  и концепции  из  существующих  web­фреймворков  (Java­фреймворки, RoR)

• Концентрация на бизнес­логике приложения

• Простая и эффективная система безопасности

• Использование  преимуществ  Scala  как  базового  языка (контроль  типов,  встроенная  обработка  XML, функциональные элементы)

• View­First предпочтительнее MVC­модели

• Изначальная поддержка AJAX и Comet

• Используется  в  таких  компаниях,  как  Nowell,  SAP, Innovation Games, Foursquare, Untyped и другими

Page 20: Scala and LiftWeb presentation (Russian)

сообщество

• Домашняя страница: http://liftweb.net/

• Google Groups (2500 участников): http://groups.google.com/group/liftweb

• Открытый исходный код на GitHub: http://github.com/dpp/liftweb/tree/master

• Wiki и треккер на Assembla: http://www.assembla.com/wiki/show/liftweb/

• Бесплатные книги:

 Exploring Lift: http://exploring.liftweb.net/

 Simply Lift: http://stable.simply.liftweb.net/

• Дружелюбное комьюнити и Поллак

Page 21: Scala and LiftWeb presentation (Russian)

быстрый старт

• Генерация приложения Scala 2.8.1 + Lift 2.2:

mvn archetype:generate \

­DarchetypeGroupId=net.liftweb \

­DarchetypeArtifactId=lift­archetype­basic_2.8.1 \

­DarchetypeVersion=2.2 \

­DarchetypeRepository=http://scala­tools.org/repo­releases \

­DremoteRepositories=http://scala­tools.org/repo­releases \

­DgroupId=ua.dn.cnc \

­DartifactId=lift_demo \

­Dversion=1.0

• Запуск сервера:

mvn jetty:run

Page 22: Scala and LiftWeb presentation (Russian)

структура проекта

Структура каталога нового проекта:

• project – Simple Build Tool (SBT) конфигурация

• src/main/resources – ресурсы проекта

• src/main/scala – исходный код на Scala

• ua.dn.cnc.Boot – конфигурация Lift приложения

• ua.dn.cnc.lib.DependencyFactory  –  Dependency Injection

• ua.dn.cnc.model.User – сущность User

• ua.dn.cnc.snippet.HelloWorld – Hello World сниппет

• src/main/webapp – web ресурсы (шаблоны, html, css, js)

• src/main/test ­ исходный код тестов

• pom.xml – Apache Maven конфигурация

Page 23: Scala and LiftWeb presentation (Russian)

mapper orm

object News extends News with LongKeyedMetaMapper[News] {    override def dbIndexes = 

UniqueIndex(title) :: super.dbIndexes}class News extends LongKeyedMapper[News] with IdPK {    def getSingleton = News

    object title extends MappedString(this, 255) {        override def dbNotNull_? = true    }    object text extends MappedString(this, 1200) {        override def dbNotNull_? = true    }    object publish extends MappedBoolean(this) {        override def dbNotNull_? = true        override def defaultValue: Boolean = true    }    object date extends MappedDate(this) {        override def dbNotNull_? = true    }}

Page 24: Scala and LiftWeb presentation (Russian)

mapper orm

Создание записи:val n = News.createn.title("Lorem ipsum")…n.save

Удаление записи:n.delete_!

Все записи:val n = News.findAll

Записи по условию:   val n = News.findAll(By(News.publish, true),                                         OrderBy(News.date, Descending),                        StartAt(0), MaxRows(10))

Записи по SQL­запросу:   val n = News.findAllByInsecureSql("select * from news " +             "where publish = 1 order by(date_c)",             IHaveValidatedThisSQL("dba", "2011­01­01"))

Page 25: Scala and LiftWeb presentation (Russian)

menu

Boot.scala:

import net.liftweb.http.LiftRulesimport net.liftweb.sitemap.Locimport net.liftweb.sitemap.Loc.Hiddenimport net.liftweb.sitemap.Loc.strLstToLinkimport net.liftweb.sitemap.Menuimport net.liftweb.sitemap.SiteMap...def boot {

...val myLoc = Loc("HomePage", "index" :: Nil, "Home Page", 

Hidden)val myMenu = Menu(myLoc)val allMenus = myMenu :: User.sitemapval mySiteMap = SiteMap(allMenus: _*)LiftRules.setSiteMap(mySiteMap)...

Page 26: Scala and LiftWeb presentation (Russian)

menu

Loc:Loc(theName:"Home", theLink:new Link(List("index")), 

theText:"Home Page")Loc("About", "info" :: "about" :: Nil, "About", Hidden)Loc("HomePage", "index" :: Nil, "Home Page", Test((req) => 

req.isIE6))Loc("Static", Link(List("static"), true, "/static/index"), 

"Static Content")Menu:

val myMenu = Menu(Loc("About", "about" :: Nil, "About", Hidden))

val helpMenu = Menu(myHelpMenuLoc, myUserHelpMenu, myTechnicalHelpMenu)

val allMenus = myMenu :: User.menus

SiteMap:LiftRules.setSiteMap(SiteMap(allMenus: _*))

HTML­вывод:<lift:Menu.builder /> или <div class="lift:Menu.builder" />

Page 27: Scala and LiftWeb presentation (Russian)

url rewriting

bootstrap.liftweb.Boot.boot:

LiftRules.rewrite.prepend(NamedPF("ArticleRewrite") {case RewriteRequest(ParsePath("article" :: id :: action :: _, _, _, _)

, _, _) =>RewriteResponse(

"article" :: action :: Nil, Map("id" ­> id))})

/article/1/edit ­> /article/edit?id=1

Page 28: Scala and LiftWeb presentation (Russian)

шаблоны

<lift:surround with="default">

<lift:bind-at name="controls"><head>

<script src="…"/> </head><div class="controls">

…</div>

</lift:bind-at>

<lift:bind-at name="content"><div class="content">

…</div>

</lift:bind-at>

</lift:surround>

index.htmldefault.html

<html> <head> … </head>

<body> <div> … <lift:bind name="controls" /> </div>

<lift:bind name="content" />

… </body></html>

Page 29: Scala and LiftWeb presentation (Russian)

snippets

class Test {def show(in: NodeSeq): NodeSeq = {

TestModel.findAll().flatMap(item =>          bind("e", in, "item" ­> Text(                    "%s: %s".format(item.title, item.text)               ))          )

}}

… <ul> <lift:Test.show> <li><e:item/></li> </lift:Test.show> </ul>…

… <ul> <li>Foo: Bar</li> <li>Fizz: Buzz</li> <li>Some title: and some text</li> </ul>…

Page 30: Scala and LiftWeb presentation (Russian)

формы

Автоматическая генерация:Model.toForm(Full("Save"), { _.save })

Snippet:private var newKeyword = ""

def keywordsForm(in: NodeSeq): NodeSeq = {        bind("entry", in,            "addNewKeyword" ­> SHtml.text("", newKeyword = _, 

"maxlength" ­> "50"),            "submitNewKeyword" ­> SHtml.submit("Добавить", 

addNewKeyword))   }

private def addNewKeyword() {        val kw = 

KeywordsModel.create        kw.keyword(newKeyword)        kw.save

}

… <lift:clazz.keywordsForm form="POST"> <entry:addNewKeyword /> <entry:submitNewKeyword /> </lift:clazz.keywordsForm>…

Page 31: Scala and LiftWeb presentation (Russian)

ссылки

• Обзор языка программирования Scala

• Статьи на Habrahabr

• Programming Scala

• Scala Reference Manuals

• Scala Style Guide

• Exploring Lift

• Lift Wiki

Page 32: Scala and LiftWeb presentation (Russian)

Спасибо за внимание и EOF