プラグイン

□未翻訳

□翻訳中

□翻訳完了(Yota Ichino)

■レビュー(Omi Chiba)

プラグイン

プラグインはアプリケーションのファイルのサブセットです。

A plugin is any subset of the files of an application.

そして、他にもこの様な意味があります:

and we really mean any:

    • プラグインはモジュール、モデル、コントローラ、ビューではなく、むしろモジュール、モデル、コントローラとビューの両方またはいずれか一方を含んだものです。

    • プラグインは機能的に自律的である必要はありませんし、他のプラグインや特定のユーザが作った関数に依存してもかまいません。

    • プラグインはプラグインシステムでは無いため、ある程度の独立を実現するためのルールを決めようとしていますが、登録や独立といった概念はありません。

    • あなたのアプリケーション用のプラグインについて説明しており、web2pyのプラグインではありません。

    • A plugin is not a module, it not a model, it is not a controller, it not a view, yet it may contain modules, models, controllers and/or views.

    • A plugin does not need to be functionally autonomous and it may depend on other plugins or specific user code.

    • A plugin is not a plugins system and therefore has no concept of registration nor isolation, although we will give rules to try to achieve some isolation.

    • We are talking about a plugin for your app, not a plugin for web2py.

では、なぜプラグインと呼ばれているのでしょうか?それは、アプリケーションのサブセットをパッキングし他のアプリケーション上にアンパック(つまりプラグイン)するメカニズムを提供するからです。この定義に基づき、あなたのアプリケーション中のファイルはプラグインとして扱われます。

So why is it called a plugin? Because it provides a mechanism for packing a subset of an app and unpacking it over another app (i.e. plug-in). Under this definition, any file in your app can be treated as a plugin.

アプリケーションが配布されるとき、そのプラグインはパックされ、それと一緒に配布されます。

When the app is distributed, its plugins are packed and distributed with it.

プラクティスで、adminはアプリケーションから独立してパッキングやアンパッキングするためのインターフェイスを提供します。接頭語plugin_nameの名前をもつアプリケーションのファイルとフォルダは:

In practice, the admin provides an interface for packing and unpacking plugins separately from your app. Files and folder of your application that have names with the prefixplugin_name can be packed together into a file called:

web2py.plugin.name.w2p

というファイルへ格納され一緒に配布されます。

and distributed together.

adminがそれらのファイルは一緒に配布されるべきであることを理解し、異なるページに表示することを除いて、プラグインを含むファイルはweb2pyによって他のファイルと同様に扱われます。

The files that compose a plugin are not treated by web2py any differently than other files except that admin understands from their names that they are meant to be distributed together, and it displays them in a separate page:

しかし実際は、上記の定義によると、これらのプラグインはadminなどによって認知されたプラグインより一般的です。

Yet as a matter of fact, by the definition above, these plugins are more general than those recognized as such by admin.

実際、私たちは2つのタイプのプラグインだけ考えることにします:

In practice we will only be concerned with two types of plugins:

  • コンポーネントプラグイン。これは前節で定義されたようなコンポーネントを含んだプラグインです。コンポーネントプラグインは1つ以上のコンポーネントを含めることができます。上記のcommentsコンポーネントを含んだplugin_commentsの例で考えることができます。他の例はtaggingコンポーネントとプラグインによって定義されたいくつかのデータベーステーブルを共有するtag-cloudコンポーネントを含んだplugin_taggingなどです。

    • レイアウトプラグイン。これはレイアウトビューとそれに必要な静的なファイルを含んだプラグインです。プラグインが適用されるとアプリケーションに新しい印象と見栄えを与えます。

    • Component Plugins. These are plugins that contain components as defined in the previous section. A component plugin can contain one or more components. We can think for example of a plugin_comments that contains the comments component proposed above. Another example could be plugin_tagging that contains a taggingcomponent and a tag-cloud component that share some database tables also defined by the plugin.

    • Layout Plugins. These are plugins that contain a layout view and the static files required by such layout. When the plugin is applied it gives the app a new look and feel.

上記の定義により、前節で製作された、例えば"controllers/contact.py"はプラグインです。それらを1つのアプリケーションから他のアプリケーションに移動することができ、それらが定義したコンポーネントを使用できます。まだ、それらはadminによりそういうものとして認められていません。解決するべき2つの問題があります:

By the above definitions, the components created in the previous section, for example "controllers/contact.py", are already plugins. We can move them from one app to another and use the components they define. Yet they are not recognized as such by admin because there is nothing that labels them as plugins. So there are two problems we need to solve:

  • 慣例に従いプラグインファイルに名前を付けることでadminは同じプラグインの属するものとして認識できます。

  • もしモデルファイルがプラグインにあったら、慣例を決めることで名前空間を汚さず、互いに衝突することを避けることをできます。

    • Name the plugin files using a convention, so that admin can recognize them as belonging to the same plugin

    • If the plugin has model files, establish a convention so that the objects it defines do not pollute the namespace and do not conflict with each other.

nameと呼ばれるプラグインを前提としましょう。ここには従われるべきルールがあります:

Let's assume a plugin is called name. Here are the rules that should be followed:

ルール 1: プラグインモデルとコントローラはそれぞれ以下のように呼ばれる必要があり

Rule 1: Plugin models and controllers should be called, respectively

  • models/plugin_name.py

  • controllers/plugin_name.py

そして、それぞれのフオルダ内にあるプラグインビュー、モデル、staticとprivateファイルは以下のように呼ばれる必要があります:

and plugin views, modules, static, and private files should be in folders called, respectively:

  • views/plugin_name/

  • modules/plugin_name/

  • static/plugin_name/

  • private/plugin_name/

ルール 2: プラグインモデルは下記の名前で始まるオブジェクトを定義するだけで可能です。

Rule 2: Plugin models can only define objects with names that start with

  • plugin_name

  • PluginName

  • _

ルール 3: プラグインモデルは下記の名前から始まるsession変数を定義するだけでできます。

Rule 3: Plugin models can only define session variables with names that start with

  • session.plugin_name

  • session.PluginName

ルール 4: プラグインはライセンスとドキュメントを含まなくてはなりません。ここに置かれるべきです:

Rule 4: Plugins should include license and documentation. These should be placed in:

  • static/plugin_name/license.html

  • static/plugin_name/about.html

ルール 5: プラグインは"db.py"雛形で定義されたグローバルオブジェクトだけに依存できます。すなわち

Rule 5: The plugin can only rely on the existence of the global objects defined in scaffolding "db.py", i.e.

  • dbというデータベースのコネクション

    • authというAuthインスタンス

    • crudというCrudインスタンス

    • serviceというServiceインスタンス

    • a database connection called db

    • an Auth instance called auth

    • a Crud instance called crud

    • a Service instance called service

さらに洗練され1つ以上のdbインスタンスが存在する場合のパラメータ設定を持っているプラグインもあります。

Some plugins may be more sophisticated and have a configuration parameter in case more than one db instance exists.

ルール 6: もしプラグインにパラメータを設定する必要があるならば、以下で説明するPluginManagerで設定されるべきです。

Rule 6: If a plugin needs configuration parameters, these should be set via a PluginManager as described below.

PluginManager

上記のルールによって以下を確実にすることができます:

By following the above rules we can make sure that:

    • adminは全てのplugin_nameファイルと単一の部品としてのフォルダを認識する。

    • プラグインはお互いに干渉しない。

    • admin recognizes all the plugin_name files and folder as part of a single entity.

    • plugins do not interfere with each other.

上記のルールはプラグインのバージョンと依存関係の問題を解決しません。この本の範囲を超えています。

The rules above do not solve the problem of plugin versions and dependencies. That is beyond our scope.

コンポーネントプラグイン

component plugin

コンポーネントプラグインはコンポーネントを定義するプラグインです。コンポーネントは通常データベースに接続し独自のモデルを定義します。

Component plugins are plugins that define components. Components usually access the database and define with their own models.

ここで前に書いたコードと同様だが前述のルールに従い、commentsコンポーネントをcomments_pluginに変えます。

Here we turn the previous comments component into a comments_plugin by using the same code we wrote before, but following all of the previous rules.

1つ目に、"models/plugin_comments.py"と呼ばれるモデルを作成します:

First, we create a model called "models/plugin_comments.py":

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

db.define_table('plugin_comments_comment',

Field('body','text', label='Your comment'),

Field('posted_on', 'datetime', default=request.now),

Field('posted_by', db.auth_user, default=auth.user_id))

db.plugin_comments_comment.posted_on.writable=False

db.plugin_comments_comment.posted_on.readable=False

db.plugin_comments_comment.posted_by.writable=False

db.plugin_comments_comment.posted_by.readable=False

def plugin_comments():

return LOAD('plugin_comments','post',ajax=True)

(プラグインの組み込みを単純化する関数を定義する最後の2行に注意してください。)

(notice the last two lines define a function that will simplify the embedding of the plugin)

2つ目は、"controllers/plugin_comments.py"を定義します:

Second, we define a "controllers/plugin_comments.py"

1.

2.

3.

4.

5.

@auth.requires_login()

def post():

comment = db.plugin_comments_comment

return dict(form=crud.create(comment),

comments=db(comment.id>0).select())

3つ目は"views/plugin_comments/post.load"と呼ばれるビューを作成します:

Third, we create a view called "views/plugin_comments/post.load":

1.

2.

3.

4.

5.

6.

7.

{{for comment in comments:}}

<div class="comment">

on {{=comment.posted_on}} {{=comment.posted_by.first_name}}

says <span class="comment_body">{{=comment.body}}</span>

</div>

{{pass}}

{{=form}}

そして、admin使用して配布用のプラグインをパックできます。管理者はこのプラグインを以下のように保存できます:

Now we can use admin to pack the plugin for distribution. Admin will save this plugin as:

1.

web2py.plugin.comments.w2p

admineditページで以下を自分が作成したビューに追加してプラグインをインストールするだけで、どのビューでもプラグインを使用することができます。

We can use the plugin in any view by simply installing the plugin via the edit page in adminand adding this to our own views

1.

{{=plugin_comments()}}

もちろんパラメータを取得しオプションを設定したコンポーネントを用いることでより洗練されたプラグインを製作できます。コンポーネントがより複雑になればなるほど、名前の衝突を避けるのが難しくなります。以下に記載されたプラグインマネージャーはこの問題を回避するように設計さいれています。

Of course we can make the plugin more sophisticated by having components that take parameters and configuration options. The more complex the components, the more difficult it becomes to avoid name collisions. The Plugin Manager described below is designed to avoid this problem.

プラグインマネージャー

PluginManagergluon.toolsで定義されたクラスです。内部でどの様に動作するかを説明する前に、使用方法を説明します。

The PluginManager is a class defined in gluon.tools. Before we explain how it works inside, we will explain how to use it.

前述のcomments_pluginを改善してみます。プラグインコード自身を編集しないで:

Here we consider the previous comments_plugin and we make it better. We want to be able to customize:

1.

db.plugin_comments_comment.body.label

カスタマイズできるようにしたいからです。

without having to edit the plugin code itself.

その方法を示します:

Here is how we can do it:

始めに、このように"models/plugin_comments.py"プラグインを書き換えてください:

First, rewrite the plugin "models/plugin_comments.py" in this way:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

db.define_table('plugin_comments_comment',

Field('body','text',label=plugin_comments.comments.body_label),

Field('posted_on', 'datetime', default=request.now),

Field('posted_by', db.auth_user, default=auth.user_id))

def plugin_comments()

from gluon.tools import PluginManager

plugins = PluginManager('comments', body_label='Your comment')

comment = db.plugin_comments_comment

comment.label=plugins.comments.body_label

comment.posted_on.writable=False

comment.posted_on.readable=False

comment.posted_by.writable=False

comment.posted_by.readable=False

return LOAD('plugin_comments','post.load',ajax=True)

テーブル定義を除く全てのコードがどの様にして単一の関数内で定義されるかに注意してください。また、PluginManagerのインスタンスがどの様にして作られるかにも注意してください。

Notice how all the code except the table definition is encapsulated in a single function. Also notice how the function creates an instance of a PluginManager.

あなたのアプレケーション内のそれ以外のモデル、例えば"models/db.py"で、次のようにこのプラグインを設定してください:

Now in any other model in your app, for example in "models/db.py", you can configure this plugin as follows:

1.

2.

3.

from gluon.tools import PluginManager

plugins = PluginManager()

plugins.comments.body_label = T('Post a comment')

pluginsオブジェクトは"models/db.py"のデフォルトとなる雛形アプリケーションですでにインスタンスを作成されています。

The plugins object is already instantiated in the default scaffolding app in "models/db.py"

PluginManagerオブジェクトはStorageオブジェクトのスレッドレベルでインスタンスを1つしか生成しないStorageオブジェクトです。それは同じアプリケーション内に好きなだけインスタンスを作成できることを意味しますが、(それらが同じ名前を持っていようがいまいが)それらはたった1つのPluginManager インスタンスであるかのように振る舞います。

The PluginManager object is a thread-level singleton Storage object of Storage objects. That means you can instantiate as many as you like within the same application but (whether they have the same name or not) they act as if there were a single PluginManager instance.

具体的には、どのプラグインファイルも独自のPluginManagerオブジェクトを作成し、それ自身とデフォルトパラメータを設定できます:

In particular each plugin file can make its own PluginManager object and register itself and its default parameters with it:

1.

plugins = PluginManager('name', param1='value', param2='value')

このコード以外の場所(例えば"models/db.py"へ)にそれらのパラメータを上書きできます:

You can override these parameters elsewhere (for example in "models/db.py") with the code:

1.

2.

plugins = PluginManager()

plugins.name.param1 = 'other value'

1つの場所で複数のプラグインを設定できます。

You can configure multiple plugins in one place.

1.

2.

3.

4.

5.

6.

plugins = PluginManager()

plugins.name.param1 = '...'

plugins.name.param2 = '...'

plugins.name1.param3 = '...'

plugins.name2.param4 = '...'

plugins.name3.param5 = '...'

プラグインが定義されたとき、PluginManagerは引数を取らなくてはなりません: プラグイン名とオプションでデフォルトパラメータの名前付き引数があります。しかしながら、プラグインが設定されたときに、PluginManagerコンストラクタは引数を取りません。その設定はプラグインの定義の前にされなければなりません(つまり、アルファベット順で最初に来るモデルファイルであるべきです)。

When the plugin is defined, the PluginManager must take arguments: the plugin name and optional named arguments which are default parameters. However, when the plugins are configured, the PluginManager constructor must take no arguments. The configuration must precede the definition of the plugin (i.e. it must be in a model file that comes first alphabetically).

レイアウトプラグイン

layout plugin

普通レイアウトプラグインはコードを含まずビューと静的ファイルだけなので、レイアウトプラグインはコンポーネントプラグインより単純です。とはいえ、良いプラクティスに従うべきです:

Layout plugins are simpler than component plugins because usually they do not contain code, but only views and static files. Yet you should still follow good practice:

まず始めに、"static/plugin_layout_name/"(この名前はあなたのレイアウトの名前です) というフォルダを作り、そこにあなたの静的ファイルを配置してください。

First, create a folder called "static/plugin_layout_name/" (where name is the name of your layout) and place all your static files there.

2つ目は、あなたのレイアウトと画像へのリンクを含んだ"views/plugin_layout_name/layout.html"というレイアウトファイルを作り、CSSとJavaScriptファイルを"static/plugin_layout_name/"に入れてください。

Second, create a layout file called "views/plugin_layout_name/layout.html" that contains your layout and links the images, CSS and JavaScript files in "static/plugin_layout_name/"

3つ目は、単純に読めるように"views/layout.html"を修正してください:

Third, modify the "views/layout.html" so that it simply reads:

1.

2.

{{extend 'plugin_layout_name/layout.html'}}

{{include}}

この設計の利点ははこのプラグインのユーザが複数のレイアウトをインストールできることと、ただ単に"views/layout.html"を編集することでどのデザインを適用すべきかを選択できることです。加えて、"views/layout.html"はプラグインと一緒にadminによりパックされませんので、インストール済みレイアウトのユーザコードをプラグインが上書きする心配はありません。

The benefit of this design is that users of this plugin can install multiple layouts and choose which one to apply simply by editing "views/layout.html". Moreover, "views/layout.html" will not be packed by admin together with the plugin, so there is no risk that the plugin will override the user's code in the previously installed layout.