diff options
author | Toshiaki Asai <toshi.alternative@gmail.com> | 2016-10-22 19:30:41 +0900 |
---|---|---|
committer | Toshiaki Asai <toshi.alternative@gmail.com> | 2016-10-22 19:30:41 +0900 |
commit | 1cd74a03f33b4294e5a1af7314e82ff76e81e695 (patch) | |
tree | 04d2b159ea31386bcf88bbe221a52204e924b174 | |
parent | 2afae5e4671d307195b8d622d870e485bc6e5f9c (diff) | |
parent | 5a56709b4be80f6d8bc4c87795dc609416b8bb72 (diff) | |
download | mikutter-1cd74a03f33b4294e5a1af7314e82ff76e81e695.tar.gz |
Merge branch 'topic/906-forward-intent' into develop
-rw-r--r-- | core/plugin/intent/intent.rb | 53 | ||||
-rw-r--r-- | core/plugin/intent/model/intent_token.rb | 31 |
2 files changed, 70 insertions, 14 deletions
diff --git a/core/plugin/intent/intent.rb b/core/plugin/intent/intent.rb index 12cc69fc..4d3d9bf6 100644 --- a/core/plugin/intent/intent.rb +++ b/core/plugin/intent/intent.rb @@ -20,6 +20,11 @@ Plugin.create(:intent) do defevent :intent_select, prototype: [Enumerable, tcor(URI, String, Retriever::Model)] + # IntentTokenの次にあたるintentを発生させる。 + defevent :intent_forward, + priority: :ui_response, + prototype: [Plugin::Intent::IntentToken] + # _model_ を開く方法を新しく登録する。 # ==== Args # [model] サポートするModelのClass @@ -63,30 +68,43 @@ Plugin.create(:intent) do end end + on_intent_forward do |intent_token| + case intent_token[:source] + when Retriever::Model + open_model(intent_token[:source], token: intent_token) + else + open_uri(intent_token.uri, token: intent_token) + end + end + # _uri_ をUI上で開く。 # このメソッドが呼ばれたらIntentTokenを生成して、開くことを試みる。 # open_modelのほうが高速なので、modelオブジェクトが存在するならばopen_modelを呼ぶこと。 # ==== Args # [uri] 対象となるURI - def open_uri(uri) + # [token:] 親となるIntentToken + def open_uri(uri, token: nil) model_slugs = Plugin.filtering(:model_of_uri, uri.freeze, Set.new).last if model_slugs.empty? error "model not found to open for #{uri}" return end - intents = model_slugs.inject(Set.new) do |memo, model_slug| - memo.merge(Plugin.filtering(:intent_select_by_model_slug, model_slug, Set.new).last) + intents = model_slugs.lazy.flat_map{|model_slug| + Plugin.filtering(:intent_select_by_model_slug, model_slug, []).last + } + if token + intents = intents.reject{|intent| token.intent_ancestors.include?(intent) } end - if intents.empty? + head = intents.first(2) + case head.size + when 0 error "intent not found to open for #{model_slugs.to_a}" return - end - if intents.size == 1 - intent = intents.to_a.first + when 1 Plugin::Intent::IntentToken.open( uri: uri, - intent: intent, - parent: nil) + intent: head.first, + parent: token) else Plugin.call(:intent_select, intents, uri) end @@ -98,16 +116,23 @@ Plugin.create(:intent) do # このメソッドはヒントとして _model_ を与えるため、探索が発生せず高速に処理できる。 # ==== Args # [model] 対象となるRetriever::Model - def open_model(model) + def open_model(model, token: nil) intents = Plugin.filtering(:intent_select_by_model_slug, model.class.slug, Set.new).last - # TODO: intents をユーザに選択させる - if intents.size == 1 - intent = intents.to_a.first + if token + intents = intents.reject{|intent| token.intent_ancestors.include?(intent) } + end + head = intents.first(2) + case head.size + when 0 + type_strict model.uri => URI + open_uri(model.uri, token: token) + when 1 + intent = head.first Plugin::Intent::IntentToken.open( uri: model.uri, model: model, intent: intent, - parent: nil) + parent: token) else Plugin.call(:intent_select, intents, model) end diff --git a/core/plugin/intent/model/intent_token.rb b/core/plugin/intent/model/intent_token.rb index 2279c0ce..cd14286f 100644 --- a/core/plugin/intent/model/intent_token.rb +++ b/core/plugin/intent/model/intent_token.rb @@ -5,12 +5,18 @@ module Plugin::Intent field.string :uri, required: true field.has :model, Retriever::Model field.has :intent, Plugin::Intent::Intent, required: true + field.has :parent, Plugin::Intent::IntentToken # 引数の情報からIntentTokenを作成し、それを開く def self.open(*args) self.new(*args).open end + def initialize(*rest) + super + self[:source] = self[:model] + end + # 設定された情報を使ってURI又はModelを開く def open if model? @@ -25,5 +31,30 @@ module Plugin::Intent end self end + + def forward + Plugin.call(:intent_forward, self) + end + + # _self_ から親のIntentTokenを再帰的に遡って、そのIntentTokenを引数に繰り返すEnumeratorを返す。 + # ==== Return + # [Enumerator] IntentTokenを列挙する + def ancestors + Enumerator.new do |yielder| + cur = self + loop do + break unless cur + yielder << cur + cur = cur.parent + end + end + end + + # ancestorsと同じようなもの。ただし、IntentToken#intentに関して繰り返す。 + # ==== Return + # [Enumerator] Intentを列挙する + def intent_ancestors + ancestors.lazy.map(&:intent) + end end end |