Sass+Compassのチュートリアル

Sass関連のチュートリアルで、ここ一年の間に更新されたものを探してみた。

にはお目当てのものはほとんどなかったなぁ。

Sass Tutorial: Building An Online VCard With Sass & Compass

タイトルの通り、VCard を作りながらSassとCompassの作業を学ぶという内容。ワイヤーフレームを使ってデザインしているので、こっち方面が素人すぎる僕には楽しめる内容だった。

socialsectionのところの

text-indent: 100%;  
whitewhite-space: nowrap;  
overflow: hidden;

ってなんじゃろかと思ったら[CSS]画像置換「-9999px」のパフォーマンスを改善した新しいテクニックなのね。

Improve your responsive design workflow with Sass

レスポンシブ・ウェブデザインのためのグリッドシステムを作ってみようっていう内容。可変グリッドとVertical Rhythmを実装していく。

グリッドシステムは出来合いのを使うことが多いけど、どういう感じで実装されているのかを知っておけば弄りたいときに都合がいいかなと思う。

それからVertical Rhythmはこのサイトがわかりやすかった

SASS and Compass for Web Designers

スクリーンキャストだけど、時間がかかりそうなので見てない。週末用にストックしておく。

Compass以外のSassのフレームワーク

Compassのリファレンスにひと通り目を通して、Blueprintのグリッドサンプルを試したので、他のフレームワークというか最近のSass界隈の情報も仕入れたくなったのでググった。

日本語の情報はあまりないね。

Bourbon

酒にちなんだ名前は素敵。

A simple and lightweight mixin library for Sass.と銘打っているようにmixin詰め合わせた感じで、フレームワーク的にCompassに近い。

Bourbon上に構築されたBourbon Neatっていうグリッドフレームワークもあるが、これも働きたくないものは酒を飲めと暗示されているようで素敵感が漂っている。

Compass と Bourbonどっちがいいの?

sofに投稿されそうな質問(で、建設的じゃないという理由で速攻クローズされる)だが。

bourbon派の意見としては、bourbonは分かりやすいらしい。

  • 実態ファイルが見える。ただのscssファイル。なので階層構造もおそらく自由にできるはず。
  • ドキュメントが読みやすい。サンプルも付いている。
  • コンパイルが軽い。
  • 小さいライブラリなので習得にほとんど時間がかからない。

確かにドキュメントはbourbonのほうが読みやすかった。

Rubyの知識がないとコンパイル時になにやっているのかわからんという指摘もされてた。

一方でCompass派の意見として

CompassはBourbonのスーパーセットみたいなもんだからサブセットなんて必要ないじゃん、存在域がわからん(意訳)

みたいなのもあった。

結論は好きな方使え

Centurion

Centurionはresponsive web frameworkだ。Docsをみると、んーbootstrapみたいにでかいフレームワーク目指してんのかなぁと思ったが、Hacker newsでも似たような事言われてた(bootstrappyってw)

僕だったらbootstrap-sassを使うな。

Foundation

bootstrapの対抗だったらFoundationのほうが有名な気がするが、最近バージョンが上がってモバイルファーストになったらしいがよくわからん。

そもそも、フレームワーク臭がいやだなーってことでbootstapの代わりになるようなものを探し始めたのに、フレームワークの比較に収斂しつつあるなんてダメダメだ。

とはいえFoundation4は面白そうなのでそのうち触ってみようっと。

おまけ

検索してたら見つけた

Stylusのように舞い、HamlのようにSass

デザイン力とかCSS力が足りないので今年はそこら辺を強化しようとおもっているんだが、CSS拡張メタ言語のいいところは、先人の知恵をライブラリとして取り込んでコモディティ化できることかなと思っている。

既にhail2u.netでも書かれていた

様々なところで公開されているCSSのエッセンスを取り込んだ自分なりのCSS製作環境を構築するというような利用の仕方もできる。つまりはこれこそが必要とされていたスタイルシート言語ということなのではないか。Sass、そしてSassy CSS (SCSS)

Stylus(そしてnib)は構文が好みなんだけど、ユーザーの層が薄いのでとりあえずはSassに入門してみることにした。

インストール

Rubyはrbenvで入れてあるので

$ gem update --system
$ gem install sass
$ gem install compass

でok

Sassを学ぶ

ちょっと前にズルいStylus書いててStylusの構文というかそういったあたりのmix-inとかは理解しているので、構文はチュートリアルをざっと読めば理解できた。大体似たような構文だけどsigilがperl風味。

StylusがpythonっぽいとするならLESSとかSass(Scss)はperlとかrubyっぽい。そう考えるとsassはインデントでネストを表現するperlみたいな印象を受けるのでちょっと気持ち悪いし、Stylusのほうがスッキリしていて綺麗に見えるのは納得できる。だったらsassじゃなくてscssで書いたほうがいいかなぁとも思う。

次に、CSS Preprocessor Advent Calendar 2012を読めばよい。これでかなり理解が深まるが、特にOOCSSとSassは構造化の観点からCSSを考える上で非常に参考になる。

cssはクラスベースというよりはプロトタイプベースの継承って考えたほうがしっくりくるかもしれんなぁと思った。spineのextendとincludeと似たような感じだしねー。

あとは次のスライドを読めばいいですね。

Emacsの設定

M-x list-packagesからscss-modeをインストールする。

これはデフォルトで保存時にコンパイルが走ってうざいのと、インデントが4文字スペースなのでscss-mode.elを使うの通りに設定を変更しておく。

ちなみにファイルを開くとflymake関連エラーが出るけどそれは直してない。

ProductName Sass and Compass in Action
Wynn Netherland
Manning Pubns Co / 4356円 ( 2013-02-28 )


昨夜のリスト

Unquoteから始まりUpbeatsで終わる。

Hide Your Tears Because We Are In Heaven / Unquote
Last Night / Kantyze
No Ballast / Dan Habarnam
Hide U / Kosheen
Cosmic Rain / Pluton & Skyer
Block Breaker / Krakota
The Lighter / DJ SS
Heaven (NuTone Remix) / Emeli Sande
Fibreglass / Logistics
Slice Of Nature / Utah Jazz
Beneath The Mask (12"Cut) / Makai
Enemies Of The State / Gridlok
Saligia (feat. Kemo) / Enei
Protocol (Digital Bonus Track) / Spinline
Thinking Cap (Feat. Georgie) / The Upbeats

FlaskとSQLAlchemyでつくるreStructuredTextなWiki (5)

reStructuredTextをHTMLにコンバートする

まずはreStructuredTextをHTMLにコンバートするためにdocutilsをインストールします。

pip install docutils

modelを修正してreStructuredTextをHTMLにコンバートするメソッドを追加します。

from sqlalchemy import Column, Integer, String, Text, DateTime
from flaski.database import Base
from datetime import datetime
from docutils.core import publish_parts
overrides = {'doctitle_xform': 0,
             'initial_header_level': 2}

class WikiContent(Base):
    __tablename__ = 'wikicontents'
    id = Column(Integer, primary_key=True)
    title = Column(String(128), unique=True)
    body = Column(Text)
    date = Column(DateTime, default=datetime.now())

    def __init__(self, title=None, body=None, date=None):
        self.title = title
        self.body = body
        self.date = date

    def __repr__(self):
        return '<Title %r>' % (self.title)

    @property
    def html(self):
        parts = publish_parts(source=self.body,
                              writer_name="html",
                              settings_overrides=overrides
                              )
        return parts['html_body']

@propertyデコレータを使うことでcontent.html()とメソッド呼び出しではなくcontent.htmlとプロバティとしてアクセスできるようになります。setting_overridesしているのはタイトルをh1要素にしているので、トップレベルのヘッダーをh2から始めたいからです。

それからpostした時の戻り値もhtmlにコンバートしたものにします。

@app.route("/<title>", methods=["POST"])
def post_content(title=None):
    ......
    return content.html

httpieでちょっとテストしてみます

$ http --form POST http://localhost:5000/rsttest body="rst **strong** and *italic*"
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 85
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Sun, 03 Mar 2013 06:29:59 GMT

<div class="document">
<p>rst <strong>strong</strong> and <em>italic</em></p>
</div>

正しく変換されています。

テンプレートを修正する

ブラウザでアクセスした場合にもきちんとHTMLが表示されるようにJinja2テンプレートを修正します。

show_content.html

{% extends "layout.html" %}
{% block body %}
<h1>{{content.title}}</h1>
<div>{{content.html|safe}}</div>
<p>{{content.date}}</p>
{% endblock %}

content.bodyをhtmlに変更するだけですが、そのままだとHTMLタグがエスケープされてしまうのでsafeフィルターを付ける必要があります。

flaski4

クリックで書き換えられるようにする

wikiのコンテンツエリアをクリックした時にformの編集画面に切り替わるようにします。そのためにjeditableプラグインを利用するのでminifyバージョンをstaticディレクトリにダウンロードしておいてください。

これはajaxで通信するので編集画面に切り替わった際に元データをGETするためのAPIを用意しておきます。

app.pyに次の関数を追加します。

@app.route("/rst/<title>")
def show_rst(title):
    content = WikiContent.query.filter_by(title=title).first()
    if content is None:
        abort(404)
    return content.body

単にrstなデータを返しているだけです。

続いてテンプレートも修正します。

show_content.html

{% extends "layout.html" %}
{% block body %}
<h1>{{content.title}}</h1>
<div class="editable_textarea">{{content.html|safe}}</div>
<p>{{content.date}}</p>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="{{url_for('static', filename='jquery.jeditable.mini.js')}}"></script>
<script>
  $(".editable_textarea").editable("{{content.title}}", { 
      type   : 'textarea',
      submitdata: { _method: "post" },
      name     : 'body',
      loadurl  : '/rst/' + '{{content.title}}',
      rows     : 10,
      submit : 'OK',
      cancel : 'cancel',
      cssclass : "editable"
  });
</script>
{% endblock %}

jeditableで操作するためにdiv要素にクラスを追加しています。

bodyの最後にjQueryとjeditableを呼び出しています。先ほどapp.pyに追加した関数はloadurlで呼び出すようになっています。

コンテンツをクリックすると編集画面になるので

flaski5

日本酒に対する熱い思いをぶつけます。

flaski6

ここまでのGitHub

まとめ

reStructuredTextなWikiのための機能はひと通り揃いました。あとは見栄えを良くするためにStylus+Nib+Nibbleあたりでデザインをちょこまかいじればいいでしょう。

1362294513

FlaskとSQLAlchemyでつくるreStructuredTextなWiki (4)

POSTメソッドでデータを変更できるようにする

今回変更するのはapp.pyのみです。

SQLAlchemyを使ってデータを取得できるようになったので、データの追加、更新をできるようにします。そのためにはpython対話環境で行ったようにdb_sessionが必要なのでflaski.databaseモジュールをimportします。またリクエストの最後に、セッションの後片付けをする必要があります(shutdown_session)。

POST時にformにアクセスするのでflaskからrequestをインポートしています(1行目)。さらに、更新時を書き換えたいのでdatetimeモジュールもインポートしています。

from flask import Flask, render_template, abort, request
from flaski.models import WikiContent
from flaski.database import db_session
from datetime import datetime

app = Flask(__name__)
app.config['DEBUG'] = True

@app.teardown_request
def shutdown_session(exception=None):
    db_session.remove()

@app.route("/")
def hello():
    contents = WikiContent.query.all()
    return render_template("index.html", contents=contents)

@app.route("/<title>", methods=["GET"])
def show_content(title):
    content = WikiContent.query.filter_by(title=title).first()
    if content is None:
        abort(404)
    return render_template("show_content.html", content=content)

# 続く

GETでアクセスした場合にデータを取得、POSTでアクセスすると新規追加または更新を行いたいのでapp.routeのメソッドを限定します。

@app.route("/<title>", methods=["GET"])

POST用のコードが続きます。titleでデータを検索して存在しない場合には追加、存在する場合は更新処理をしています。bodyはformで渡されることを想定しています。

# 続き
@app.route("/<title>", methods=["POST"])
def post_content(title=None):
    if title is None:
        abort(404)
    content = WikiContent.query.filter_by(title=title).first()
    if content is None:
        content = WikiContent(title,
                              request.form["body"]
                              )
    else:
        content.body = request.form["body"]
        content.date = datetime.now()
    db_session.add(content)
    db_session.commit()
    return content.body

if __name__ == "__main__":
    app.run()

HTTP経由でデータの追加更新をテストする

HTMLでフォームを用意するのは面倒なので、今回はhttpieを利用してコマンドラインから操作してみます。

pipでインストールします

pip install httpie # $HOME/.virtualenvs/flaski/binにインストールされます

新規データを登録します。app.pyを実行してサーバーを起動しておくのを忘れないでください。

$ http --form POST http://localhost:5000/httpie body="test from httpie"
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 16
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Sun, 03 Mar 2013 04:09:36 GMT
test from httpie

--formオプション(または-f)をつけるとformで送られます。データが新規に追加されていることをブラウザで確認します。

データが既に存在する場合には更新されることも確認します。

$ http --form POST http://localhost:5000/httpie body="modified from httpie"

まとめ

FlaskiにPOST経由でのデータ追加、更新を実装しました。

ここまでのGitHub

FlaskとSQLAlchemyでつくるreStructuredTextなWiki (3)

Flaskでモデルを使う

先に用意したモデルをFlaskで使うにモデルをimportします。

ルートにアクセスしたらコンテンツのタイトル一覧を表示します。さらに、/titleにアクセスしたら内容を表示するようにします。

app.py

from flask import Flask, render_template, abort
from flaski.models import WikiContent

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route("/")
def hello():
    contents = WikiContent.query.all()
    return render_template("index.html", contents=contents)

@app.route("/<title>", methods=["GET"])
def show_content(title):
    content = WikiContent.query.filter_by(title=title).first()
    if content is None:
        abort(404)
    return render_template("show_content.html", content=content)

if __name__ == "__main__":
    app.run()

database.pyでBaseクラスにqueryメソッドを追加しておいたので、WIkiContentクラスから、allで全件検索、filter_byでフィルタリングができるようになっています。

app.routeで<>で囲むと変数としてキャプチャしています。title名で検索をかけ、データが存在しない場合は404エラーを返します(abort(404))。

index.html

{% extends "layout.html" %}
{% block body %}
<h1>Flaski</h1>
<img src="{{url_for('static', filename='snake.jpg')}}" alt="snake"/>
<ul>
{% for content in contents %}
<li><a href="{{url_for('show_content', title=content.title)}}">{{content.title}}</a></li>
{% endfor%}
</ul>
{% endblock %}

for文でcontentsをループさせ、タイトルをリンク付きでリスト表示させる処理を新たに追加しています。タイトルはapp.pyから送る必要がないので、ハードコードするようにしました。

新たに個別のコンテンツ用のテンプレートも用意します

show_content.html

{% extends "layout.html" %}
{% block body %}
<h1>{{content.title}}</h1>
<div>{{content.body}}</div>
<p>{{content.date}}</p>
{% endblock %}

コンテンツがリスト表示されることを確認します。

flaski2

ここまでのGitHub

まとめ

FlaskとSQLAlchemyを連携させてデータ検索、表示するようにしました。

FlaskとSQLAlchemyでつくるreStructuredTextなWiki (2)

SQLAlchemyを使う

SQLAlchemyを使ってModelをデザインしていきます。今回はdeclarativeを使い、RDBにSQLiteを利用します。

modelは一ヶ所で管理したいのでディレクトリを新たに用意します。

mkdir flaski # flaski/flaski
cd flaski
touch __init__.py

ディレクトリをmoduleとして呼び出したいので、__init__.pyという空のファイルを用意します。flaski/flaski以下は次のファイル構成になります。

├── flaski
    ├── __init__.py
    ├── database.py
    └── models.py

作成するのはWikiなのでタイトル、内容、タイムスタンプをデータベースに記録します。

models.py

from sqlalchemy import Column, Integer, String, Text, DateTime
from flaski.database import Base
from datetime import datetime

class WikiContent(Base):
    __tablename__ = 'wikicontents'
    id = Column(Integer, primary_key=True)
    title = Column(String(128), unique=True)
    body = Column(Text)
    date = Column(DateTime, default=datetime.now())

    def __init__(self, title=None, body=None, date=None):
        self.title = title
        self.body = body
        self.date = date

    def __repr__(self):
        return '<Title %r>' % (self.title)

WikiContentクラスではそれぞれの属性の型や主キー、ユニークかどうかなどを指定しています。__repr__メソッドでは出力した時にどう表示させるかを定義しています。

続いて、database.py

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import os

databese_file = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'wiki.db')
engine = create_engine('sqlite:///' + databese_file, convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()

def init_db():
    import flaski.models
    Base.metadata.create_all(bind=engine)

database.pyでは実際に利用されるデータベースエンジンの設定をしています。今回はSQLiteを使っています(6行目) init_dbはデータベース初期化のための関数です。

データベース初期化

python対話環境を起動してデータベースを初期化します。

>>> from flaski.database import init_db
>>> init_db()

flaski/flaski/wiki.dbが作成されているので確認してみます。

sqlite3 flaski/wiki.db
sqlite> .schema 
CREATE TABLE wikicontents (
    id INTEGER NOT NULL, 
    title VARCHAR(128), 
    body TEXT, 
    date DATETIME, 
    PRIMARY KEY (id), 
    UNIQUE (title)
);

続いて対話環境からデータを登録してみます

>>> from flaski.database import db_session
>>> from flaski.models import WikiContent
>>> c1 = WikiContent("Flask", "micro framework")
>>> db_session.add(c1)
>>> db_session.commit()
>>> c2 = WikiContent("python", "pppython")
>>> c3 = WikiContent("kobito", "kakure-momojiri")
>>> db_session.add(c2)
>>> db_session.add(c3)
>>> db_session.commit()

確認してみます

$ sqlite3 flaski/wiki.db 
SQLite version 3.7.10 2012-01-16 13:28:40
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from wikicontents;
1|Flask|micro framework|2013-03-03 09:23:03.721257
2|python|pppython|2013-03-03 09:23:03.721257
3|kobito|kakure-momojiri|2013-03-03 09:23:03.721257

ここまでのGitHub

まとめ

SQLAlchemyのdeclarativeを使ってモデル構築と、pythonからデータベースの初期化、データの登録を行いました。

FlaskとSQLAlchemyでつくるreStructuredTextなWiki (1)

初めてのFlaskアプリ

ディレクトリを用意します。

mkdir flaski
cd flaski

以下のコードをapp.pyとして保存します。ちなみにFlaskのサイトに載っているものです。

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

Flaskで開発する準備が整っていれば、python app.pyと叩けば127.0.0.1:5000でウェブサーバーが起動します。

/にアクセスした場合にHello Worldという文字列を返すように設定して(4-6行目)、app.runでアプリを起動させています。

$ python app.py
 * Running on http://127.0.0.1:5000/

flaski1

テンプレートの導入

単なる文字列だと味気無いのでテンプレートエンジンを使ってもう少し複雑なHTMLを表示してみます。ディレクトリの構成を表示しておきます。

.
├── app.py
├── static
│   └── snake.jpg
└── templates
    ├── index.html
    └── layout.html

cssや画像などのファイルはstaticというディレクトリに配置します。今回はsnake.jpgを表示してみます。

FlaskのテンプレートエンジンはJinja2です。Flask内でテンプレートを扱うにはrender_template関数を用い、テンプレートはtemplatesディレクトリに配置します。

templatesディレクトリにはlayout.html,index.htmlの2つのファイルを用意します。

layout.html

<!DOCTYPE html>
<html>
  <head>
    <title>flaski</title>
  </head>
  <body>
    {% block body %}{% endblock %}
  </body>
</html>

index.html

{% extends "layout.html" %}
{% block body %}
<h1>{{title}}</h1>
<img src="{{url_for('static', filename='snake.jpg')}}" alt="snake"/>
{% endblock %}

{{}}で囲むと変数を展開することができます。今回はtitleをapp.pyのrender_templateで渡しています。url_forはエンドポイントを指定するとURLに展開する関数です。

app.pyはrender_templateをインポートしてhello関数で使うようにします。

また今回からデバッグモードで動かすようにapp.configをいじっています(3行目)ので、ファイル更新時に自動リスタートしたり、エラーがあればブラウザにデバッグのための情報が出力されるようになります。

from flask import Flask, render_template
app = Flask(__name__)
app.config['DEBUG'] = True

@app.route("/")
def hello():
    return render_template("index.html", title="Flaski")

if __name__ == "__main__":
    app.run()

先ほどと同様にhttp://127.0.0.1:5000/にアクセスすると今度は画像つきのHTMLが表示されます。

flaski2

ここまでのGitHub

まとめ

FlaskでJinja2のテンプレートエンジンを使ってみました。

Flaskは何であって何でないかによると

Flask itself just bridges to Werkzeug to implement a proper WSGI application and to Jinja2 to handle templating.

ということなので、テンプレートエンジンはJinja2を利用するのがベストです。

補足

Jinja2自体はその上に別の構文を被せることができるので、JadeやHamlも利用することができます。

個人的にはインデントでネストを表現するJadeの構文を気に入っているのでPyJadeを使うことが多いです。

FlaskとSQLAlchemyでつくるreStructuredTextなWiki (0)

Persistentの流れから、次はFlask,SQLAlchemy,Jinja2でもやりますかねみたいな話になったので、サーチかけたんだけどいまいち興味ありそうなヒトがいなさそうなので、Wikiをつくることを題材にしてこっちに書いていくことにした。

興味ありなヒトがいそうだったらハンズオンしてもいいかなぁ。まぁどうせみんなYesodなんでしょうけどねー

仮想環境構築のためのライブラリを導入

仮想環境下で動かしたいので、pip,virtualenv,virtualenvwrapperの3つをインストールします。

curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
sudo python get-pip.py
sudo pip virtualenv
sudo pip install virtualenvwrapper

.bashrcに以下の行を追加(osx+homebrewの場合)してsourceもする(source ~/.bashrcとか)。

source /usr/local/share/python/virtualenvwrapper.sh

仮想環境を構築

今回つくるwikiの名前をflaskiにするので、flaskiという名前の仮想環境をつくります。

mkvirtualenv flaski
New python executable in flaski/bin/python
Installing setuptools............done.
Installing pip...............done.
virtualenvwrapper.user_scripts creating /Users/kzfm/.virtualenvs/flaski/bin/predeactivate
virtualenvwrapper.user_scripts creating /Users/kzfm/.virtualenvs/flaski/bin/postdeactivate
virtualenvwrapper.user_scripts creating /Users/kzfm/.virtualenvs/flaski/bin/preactivate
virtualenvwrapper.user_scripts creating /Users/kzfm/.virtualenvs/flaski/bin/postactivate
virtualenvwrapper.user_scripts creating /Users/kzfm/.virtualenvs/flaski/bin/get_env_details
(flaski)localhost@kzfm:flask $

仮想環境に入っていることはプロンプトの先頭に(flaski)と表示されることでわかります。

パッケージのインストール

FlaskとSQLAlchemyをインストールします。

pip install flask
pip install sqlalchemy

インストールされたパッケージはpip freezeで出力出来ます。

Flask==0.9
Jinja2==2.6
SQLAlchemy==0.8.0b2
Werkzeug==0.8.3
wsgiref==0.1.2

まとめ

Flaskで開発するための環境を構築しました。次からは実際にFlaskでwafを作っていきます。

補足

pipの使い方

逆に環境をコピーしたい場合には

pip freeze > requirements.txt

で依存するパッケージを作っておいて、別のマシンにファイルをコピーして

pip install -r requirements.txt

とやればいいので便利です。

virtualenvwrapperの使い方

  • mkvirtualenv [仮想環境名]: 仮想環境をつくる
  • workon [仮想環境名]: 仮想環境に入る
  • deactivate: 仮想環境をぬける
  • lsvirtualenv: 仮想環境一覧を表示
  • rmvirtualenv: 仮想環境を削除