File: regexp_entity.rb

package info (click to toggle)
mikutter 5.0.4%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 9,700 kB
  • sloc: ruby: 21,307; sh: 181; makefile: 19
file content (62 lines) | stat: -rw-r--r-- 3,350 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# -*- coding: utf-8 -*-
require_relative 'blank_entity'

module Diva::Entity

=begin rdoc
特定の正規表現にマッチする部分を自動的にSegmentにするEntity。

==== Example

    class Sample < Diva::Model
      entity_class Diva::Entity::RegexpEntity.
        filter(/:(?:\w+):/, ->s{ s.merge(open: 'https://...') }). # :???: をクリックされたら対応する絵文字の画像(https://...)を開く
        filter(/@(?:\w+)/, ->s{ s.merge(open: "https://social.mikutter.hachune.net/@#{s[:url]}") }) # @??? をクリックされたらsocial.mikutter.hachune.netのプロフィールページを開く
    end

=end
  class RegexpEntity < BlankEntity
    class << self
      # 正規表現ルールを定義する
      # ==== Args
      # [regexp] Regexp Segmentを自動生成するための正規表現
      # [generator:]
      # Proc テキストを装飾する範囲を表わすHashを引数として受け取って、それを加工して返すProc。
      # 引数はHashひとつだけで、加工する必要がなければ、引数の内容をそのまま返す。
      # ===== Argument of generator
      # 引数 _generator:_ のProcに渡されるHashは、以下のキーを持つ
      # [:message] Diva::Model このEntityが装飾する本文を持っているModel
      # [:range] Range 装飾する範囲(文字数)。
      # [:face] String _:message_ の本文中の _range_ の範囲にあるテキスト。これを書き換えると、実際の本文は変わらないが、表示上はこの内容に置き換わる。
      # [:url] String 歴史的経緯でこのような名前になっているがURLとは限らない。_:message_ の本文中の _range_ の範囲にあるテキスト。 _:face_ と違って、書き換わる前の内容が格納されている。
      # [:open] Diva::Model|URI|nil デフォルトでは存在しない。内容を指定すると、UI上で本文の _:range_ の範囲がクリックされた時に、 :open イベントでそれを開くようになる。
      # [:callback] Proc|nil 利用は非推奨。できるだけ _:open_ を使う。デフォルトでは存在しない。内容を指定すると、UI上で本文の _:range_ の範囲がクリックされた時に、これが呼ばれるようになる。指定されている場合、 _:open_ より優先される。
      # ==== Return
      # Class その正規表現を自動でリンクにする新しいEntityクラス
      def filter(regexp, generator: ret_nth)
        Class.new(self) do
          define_method(:initialize) do |*rest|
            super(*rest)
            segments = Set.new(@generate_value)
            self.message.to_show.scan(regexp) do
              match = Regexp.last_match
              pos = match.begin(0)
              body = match.to_s.freeze
              if not segments.any?{ |this| this[:range].include?(pos) }
                segments << generator.(
                  message: message,
                  from: :regexp,
                  slug: :urls,
                  range: Range.new(pos, pos + body.size, true),
                  face: body,
                  url: body).freeze
              end
            end
            @generate_value = segments.sort_by{ |r| r[:range].first }.freeze
          end
        end
      end
    end

  end
end