Crystal (язык программирования)

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 23:14, 8 июня 2016.

Введение

Crystal – (произносится [ ˈkrɪs.təl ] )это язык программирования, который похож на Ruby, но компилируется в машинный код и является более эффективным за счет запрета динамической типизации, которая является одним из аспектов Ruby.

Статус

  • Проект находится в альфа версии.
  • Компилятор написан на Crystal.

Особенности

  • Имеет схожий или почти похожий на Ruby синтаксис
  • Статические типы проверяются, но без необходимости указывать тип переменных или аргументов метода.
  • Возможно вызвать C код, написав обвязку к нему на Crystal
  • Есть оценка времени компиляции и генерации кода, дабы избежать шаблонность кода.
  • Эффективная компиляция в машинный код.

Обзор

в примерах кода, комментарий #=> используется, чтобы показать значение выражения. Например:

a = 1 + 2
a #=> 3

Комментарий :: используется для отображения типа переменной.

s = "hello"
# s :: String

Давайте начнем с двух примеров, чтобы ознакомиться с языком.

Hello World!

Классическая "hello world" программа выглядит так на Crystal:

puts "Hello world!"

Как вы можете видеть, главная программа – это просто программа сама по себе. Не нужно определять "main&quot функцию или что-то подобное.

HTTP-сервер

Чуть более интересным примером является HTTP-сервер:

require "http/server"

server = HTTP::Server.new(8080) do |request|
  HTTP::Response.ok "text/plain", "Hello world! The time is #{Time.now}"
end

puts "Listening on http://0.0.0.0:8080"
server.listen
  • Подключаем код из других файлов:

    require "http/server"
    
  • Определяем локальные переменные без необходимости определять их тип:

    server = HTTP::Server.new ...
    
  • Вызываем методы (или отправляем сообщения) на объекты.

    HTTP::Server.new(8000) ...
    ...
    Time.now
    ...
    puts "Listening on http://0.0.0.0:8080"
    ...
    server.listen
    
  • Вы можете использовать блоки кода или просто блоки, которые являются очень удобным способом повторного использования кода, и получить некоторые преимущества "функционального" мира:

    HTTP::Server.new(8080) do |request|
      ...
    end
    
  • Вы можете легко создавать строки с включенным контентом (это называется интерполяция строк). Язык также имеет другой синтаксис для создания массивов, хэшей, рядов, кортежей и многого другого:

    "Hello world! The time is #{Time.now}"
    

Установка

После того как вы установили компилятор, используя методы ниже, убедитесь, что вы прочитали статью про использование компилятора, дабы эффективно использовать его.

Из tar.gz

Если по какой-либо причине вы не можете или не хотите использовать один из предыдущих методов установки, вы можете загрузить Crystal в виде автономного .tar.gz файла со всем необходимым для начала работы.

Последние релизы можно найти на GitHub: https://github.com/manastech/crystal/releases

Скачайте файл для вашей платформы и разархивируйте. Внутри будет доступно bin/crystal.

Чтобы проще использовать это, вы можете создать символьную ссылку:

ln -s [full path to bin/crystal] /usr/local/bin/crystal

Затем вы можете вызвать компилятор, просто набрав crystal.

Из исходников

Если вы хотите стать контрибутором, вы, наверное, хотите установить Crystal из исходников. Но Crystal написан на Crystal! Поэтому для начала вам необходимо использовать один из предыдущих методов для использования компилятора.

Вам также будет необходим LLVM 3.5 или 3.6. Если Вы используете Mac и Homebrew, то LLVM будет автоматически сконфигурирован для Вас, просто добавьте флаг --with-llvm при установке Crystal.

Потом склонируйте репозиторий:

git clone https://github.com/manastech/crystal.git

и все готово.

Чтобы собрать свою личную версию компилятора, запустите make. Новый компилятор будет размещен в .build/crystal.

Будьте уверены, что установили все нужные библиотеки. Также советую Вам прочитать contributing guide.

В репозитории Вы также можете найти скрипт враппера в bin/crystal. Этот скрипт запустит глобально установленный компилятор или тот, который вы только что собрали (если имеется).

На Arch Linux

Arch Linux включает в себя компилятор Crystal в хранилище Сообщества.

Установка

sudo pacman -S crystal

На Debian и Ubuntu

В Debian вы можете использовать официальный Crystal репозиторий.

Установка репозитория

Во-первых, вы должны добавить репозиторий в вашу APT конфигурацию. Для легкой установки просто запустите в командной строке:

  curl http://dist.crystal-lang.org/apt/setup.sh | sudo bash

Это добавит ключ подписи и конфигурацию репозитория. Если вы предпочитаете делать это вручную, выполните:

apt-key adv --keyserver keys.gnupg.net --recv-keys 09617FD37CC06B54
echo "deb http://dist.crystal-lang.org/apt crystal main" > /etc/apt/sources.list.d/crystal.list

Установка

После того, как репозиторий настроен, Вы готовы к установке Crystal:

sudo apt-get install crystal

Обновление

Вы можете обновить Crystal с помощью:

sudo apt-get update
sudo apt-get install crystal

На Mac OSX, используя Homebrew

Для легкой установки Crystal на Mac, Вы можете использовать Homebrew.

brew update
brew install crystal-lang

Если вы планируете стать контрибутором, вам будет полезно установить LLVM. Так что замените последнюю строчку с:

brew install crystal-lang --with-llvm

На RedHat и CentOS

В RedHat вы можете использовать официальный Crystal репозиторий.

Установка из репозитория

Во-первых, вы должны добавить репозиторий в вашу YUM конфигурацию. Для легкой установки просто запустите в командной строке:

  curl http://dist.crystal-lang.org/rpm/setup.sh | sudo bash

Это добавит ключ подписи и конфигурацию репозитория. Если вы предпочитаете делать это вручную, выполните:

rpm --import http://dist.crystal-lang.org/rpm/RPM-GPG-KEY

cat > /etc/yum.repos.d/crystal.repo <<END
[crystal]
name = Crystal
baseurl = http://dist.crystal-lang.org/rpm/
END

Установка

После того, как репозиторий настроен, Вы готовы к установке Crystal:

sudo yum install crystal

Обновление

Вы можете обновить Crystal с помощью:

sudo yum update crystal

Используя компилятор

После того как Вы установили компилятор, будет доступна команда crystal.

В следующих секциях знак доллара ($) представляет коммандную строку.

Компиляция и запуск сразу

Для компиляции и запуска программы в одну команду, Вы можете вызвать crystal с одним именем файла:

$ crystal some_program.cr

Crystal файлы оканчиваются с .cr расширением.

Также можно использовать команду run:

$ crystal run some_program.cr

Создание исполняемого файла

Для создания исполняемого файла используйте команду build:

$ crystal build some_program.cr

В результате будет создан исполняемый файл some_program.

$ ./some_program

Заметка: По умолчания сгенерированные файлы недостаточно оптимизированы. Для запуска оптимизации, используйте флаг --release:

$ crystal build some_program.cr --release

Убедитесь, что вы постоянно используете --release для production-ready исполняемых файлов, и когда вы запускаете бенчмарки.

Создание проекта или библиотеки

Используйте команду init для создания Crystal проекта со стандартной структурой директорий.

$ crystal init lib MyCoolLib
      create  MyCoolLib/.gitignore
      create  MyCoolLib/LICENSE
      create  MyCoolLib/README.md
      create  MyCoolLib/.travis.yml
      create  MyCoolLib/shard.yml
      create  MyCoolLib/src/MyCoolLib.cr
      create  MyCoolLib/src/MyCoolLib/version.cr
      create  MyCoolLib/spec/spec_helper.cr
      create  MyCoolLib/spec/MyCoolLib_spec.cr
Initialized empty Git repository in ~/MyCoolLib/.git/

Другие команды и опции

Чтобы увидеть весь список команд, запустите crystal без аргументов.

$ crystal
Usage: crystal [command] [switches] [program file] [--] [arguments]

Command:
    init                     generate new crystal project
    build                    compile program file
    deps                     install project dependencies
    docs                     generate documentation
    eval                     eval code from args or standard input
    run (default)            compile and run program file
    spec                     compile and run specs (in spec directory)
    tool                     run a tool
    --help, -h               show this help
    --version, -v            show version

Чтобы увидеть опции определенной команды, используйте флаг --help после команды:

$ crystal build --help
Usage: crystal build [options] [programfile] [--] [arguments]

Options:
    --cross-compile flags            cross-compile
    -d, --debug                      Add symbolic debug info
    -D FLAG, --define FLAG           Define a compile-time flag
    --emit [asm|llvm-bc|llvm-ir|obj] Comma separated list of types of output for the compiler to emit
    -h, --help                       Show this message
    --ll                             Dump ll to .crystal directory
    --link-flags FLAGS               Additional flags to pass to the linker
    --mcpu CPU                       Target specific cpu type
    --no-color                       Disable colored output
    --no-codegen                     Don't do code generation
    -o                               Output filename
    --prelude                        Use given file as prelude
    --release                        Compile in release mode
    -s, --stats                      Enable statistics output
    --single-module                  Generate a single LLVM module
    --threads                        Maximum number of threads to use
    --target TRIPLE                  Target triple
    --verbose                        Display executed commands

Синтаксис и семантика

Исходный код программы должен иметь кодировку UTF-8.

Программа

Программа представляет собой глобальный объект, в котором вы можете определить типы, методы и локальные переменные.

# Defines a method in the program
def add(x, y)
  x + y
end

# Invokes the add method in the program
add(1, 2) #=> 3

Значение метода является значение его последнего выражения, нет необходимости явного return выражения. Тем не менее, явное return возможно:

def even?(num)
  if num % 2 == 0
    return true
  end

  return false
end

При вызове метода без приемника, как add(1, 2), поиск кода будет осуществлен в программе, если не будет найден в текущем типе или одном из его предков.

def add(x, y)
  x + y
end

class Foo
  def bar
    # invokes the program's add method
    add(1, 2)

    # invokes Foo's baz method
    baz(1, 2)
  end

  def baz(x, y)
    x * y
  end
end

Если вы хотите вызвать метод программы, даже если текущий тип определяет метод с тем же именем, вызовите его с префиксом :::

def baz(x, y)
  x + y
end

class Foo
  def bar
    baz(4, 2) #=> 2
    ::baz(4, 2) #=> 6
  end

  def baz(x, y)
    x - y
  end
end

Переменные, объявленные в программе, не видимы внутри методов:

x = 1

def add(y)
  x + y # error: undefined local variable or method 'x'
end

add(2)

Круглые скобки в вызове методов являются необязательными:

add 1, 2 # same as add(1, 2)

Литералы

Доступны несколько литералов для создания многих основных типов в языке.

C-обвязки

Crystal позволяет использовать библиотеки на C, не написав ни единой строки на C.

Кроме того, он предоставляет некоторые удобства типа `out` и `to_unsafe`, так что написание обвязок наиболее безболезненно.

Еще: C bindings on Crystal docs

Макросы

Макрос – это метод, который получает AST узлы при компиляции, и предоставляет код, который вставляется в программу.

Еще: Macros on Crystal docs

Соглашения

Следуйте этим соглашениям, чтобы Ваш код был более понятным для других разработчиков

Стиль кода

Этот стиль используется в стандартной библиотеке. Вы можете использовать его в своем проекте, чтобы сделать его знакомым другим разработчиков.

Именование

Имена типов обозначаются в CamelCase. Например:

class ParseError < Exception
end

module HTTP
  class RequestHandler
  end
end

alias NumericValue = Int32 | Int64 | Float32 | Float64

lib LibYAML
end

struct TagDirective
end

enum Time::DayOfWeek
end

Имена методов обозначаются в Underscore-case. Например:

class Person
  def first_name
  end

  def date_of_birth
  end

  def homepage_url
  end
end

Имена переменных обозначаются в Underscore-case. Например:

$global_greeting = "Hello world"

class Greeting
  @@default_greeting = "Hello world"

  def initialize(@custom_greeting=nil)
  end

  def print_greeting
    greeting = @custom_greeting || @@default_greeting
    puts greeting
  end
end

Константы обозначаются в SCREAMING-case. Например:

LUCKY_NUMBERS = [3, 7, 11]
DOCUMENTATION_URL = "http://crystal-lang.org/docs"
Сокращения

В именах классах, сокращения обозначаются в верхнем регистре. Например: HTTP, и LibXML.

В именах методов, сокращения обозначаются в нижнем регистре. Например: #from_json, #to_io.

Библиотеки

Lib имена имеют префикс Lib. Например: LibC, LibEvent2.

Директории и имена файлов

В проекте:

  • / содержит readme, любую конфигурацию проекта (например, CI или конфиги редактора), и любую другую проектную документацию (например, changelog или contributing guide).
  • src/ содержит исходный код проекта.
  • spec/ содержит спецификацию проекта, которая может быть запущена с помощью команды crystal spec.
  • bin/ содержит любые исполняемые файлы.

Пути файлов соответствую пространству имен их контента. Файлы имени класса или пространства имен определяют через underscore-case.

Например, HTTP::WebSocket определен в src/http/web_socket.cr.

Пробелы

Используйте два пробела для отступа кода внутри пространства имен, методов, блоков или других вложенных контекстах. Например:

module Scorecard  
  class Parser
    def parse(score_text)
      begin
        score_text.scan(SCORE_PATTERN) do |match|
          handle_match(match)
        end
      rescue err : ParseError
        # handle error ...
      end
    end
  end
end

В классе, отдельные определения методов, констант и внутренних определений класса c одним пробелом. Например:

module Money  
  CURRENCIES = {
    "EUR" => 1.0,
    "ARS" => 10.55,
    "USD" => 1.12,
    "JPY" => 134.15,
  }

  class Amount
    getter :currency, :value

    def initialize(@currency, @value)
    end
  end

  class CurrencyConversion
    def initialize(@amount, @target_currency)
    end

    def amount
      # implement conversion ...
    end
  end
end

Документация

Комментарии документации Crystal используют Markdown.

  • Документация должна быть расположена прямо над определениями классов, модулей и методов. Не ставьте пробелы между ними.
# A unicorn is a **legendary animal** (see the `Legendary` module) that has been
# described since antiquity as a beast with a large, spiraling horn projecting
# from its forehead.
class Unicorn
end

# Bad: This is not attached to any class.class Legendary
end
  • Документация метода включается в его содержание и детали. Первое включает в себя только первую строку, последний включает в себя всю документацию. Короче говоря, предпочтительнее:
  1. Статус цели метода или функциональность в первой строчке
  2. Дополнение в виде деталей и использования после

Например:

# Returns the number of horns this unicorn has.
#
# ```
# Unicorn.new.horns #=> 1
# ```
def horns
  @horns
end
  • Пишите от третьего лица: Возвращает количество рогов единорога вместо Возвращение количества рогов единорога.
  • Названия параметров должны быть выделены курсивом (заключены в одинарные звездочки * или подчеркивания _):
# Creates a unicorn with the specified number of *horns*.
def initialize(@horns = 1)
  raise "Not a unicorn" if @horns != 1
end
  • Блоки кода, которые имеют Crystal код могут быть окружены тройными обратными кавычками или отступом в четыре пробела.
# ```
# unicorn = Unicorn.new
# unicorn.speak
# ```

или

#     unicorn = Unicorn.new
#     unicorn.speak 
  • Текстовые блоки, например, чтобы показать вывод программы, должны быть окружены тройными обратными кавычками сопровождаемыми ключевым словом "text".
# ```text
# "I'm a unicorn"
# ```
  • Чтобы автоматически связать с другими типами, заключите их в одиночные обратные кавычки.
# the `Legendary` module
  • Для автоматического ссылки на методы, используйте хэш #horns или #index(char), и заключите его в одинарные обратные кавычки.
  • Чтобы автоматически связать с методами в других видах, используйте OtherType#method(arg1, arg2) или просто OtherType#method, и заключите его в одинарные обратные кавычки.

Например:

# Check the number of horns with `#horns`.
# See what a unicorn would say with `Unicorn#speak`.
  • Чтобы показать результат выражения внутри блока кода, используйте #=>.
1 + 2 #=> 3
Unicorn.new.speak #=> "I'm a unicorn"
  • Используйте ditto для использования тот же комментарий, как в предыдущем объявлении.
# ditto
def number_of_horns
  horns
end
  • Используйте :nodoc:, чтобы скрыть публичное определение из сгенерированной документации. "Private" и "protected" методы всегда скрыты.
class Unicorn
  # :nodoc:
  class Helper
  end
end

Полный пример

# A unicorn is a **legendary animal** (see the `Legendary` module) that has been
# described since antiquity as a beast with a large, spiraling horn projecting
# from its forhead.
#
# To create a unicorn:
#
# ```
# unicorn = Unicorn.new
# unicorn.speak
# ```
#
# The above produces:
#
# ```text
# "I'm a unicorn"
# ```
#
# Check the number of horns with `#horns`.
class Unicorn
  include Legendary

  # Creates a unicorn with the specified number of *horns*.
  def initialize(@horns = 1)
    raise "Not a unicorn" if @horns != 1
  end

  # Returns the number of horns this unicorn has
  #
  # ```
  # Unicorn.new.horns #=> 1
  # ```
  def horns
    @horns
  end

  # ditto
  def number_of_horns
    horns
  end

  # Makes the unicorn speak to STDOUT
  def speak
    puts "I'm a unicorn"
  end

  # :nodoc:
  class Helper
  end
end

Генерация документации

Чтобы создать документацию для проекта, вызовите crystal doc. Это создаст doc каталог, с doc/index.html точкой входа. Все файлы внутри корневого каталога src будут рассматриваться для генерации документации.

Ссылки