slack-block-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/README.md +62 -0
- data/Rakefile +6 -0
- data/bin/console +27 -0
- data/bin/setup +8 -0
- data/examples/slack_template_00.rb +46 -0
- data/examples/slack_template_01.rb +22 -0
- data/examples/slack_template_02.rb +28 -0
- data/examples/slack_template_03.rb +57 -0
- data/examples/slack_template_04.rb +29 -0
- data/examples/slack_template_05.rb +12 -0
- data/examples/slack_template_06.rb +53 -0
- data/examples/slack_template_07.rb +74 -0
- data/examples/slack_template_08.rb +77 -0
- data/examples/slack_template_09.rb +53 -0
- data/lib/slack-block-kit.rb +1 -0
- data/lib/slack/block_kit.rb +38 -0
- data/lib/slack/block_kit/block.rb +41 -0
- data/lib/slack/block_kit/block/actions_block.rb +35 -0
- data/lib/slack/block_kit/block/context_block.rb +30 -0
- data/lib/slack/block_kit/block/divider_block.rb +17 -0
- data/lib/slack/block_kit/block/image_block.rb +44 -0
- data/lib/slack/block_kit/block/section_block.rb +55 -0
- data/lib/slack/block_kit/composition_objects/confirmation_dialog.rb +59 -0
- data/lib/slack/block_kit/composition_objects/filter.rb +38 -0
- data/lib/slack/block_kit/composition_objects/option.rb +57 -0
- data/lib/slack/block_kit/composition_objects/option_group.rb +34 -0
- data/lib/slack/block_kit/composition_objects/text.rb +61 -0
- data/lib/slack/block_kit/element.rb +41 -0
- data/lib/slack/block_kit/element/button_element.rb +48 -0
- data/lib/slack/block_kit/element/channels_select_element.rb +31 -0
- data/lib/slack/block_kit/element/conversations_select_element.rb +43 -0
- data/lib/slack/block_kit/element/date_picker_element.rb +56 -0
- data/lib/slack/block_kit/element/external_select_element.rb +38 -0
- data/lib/slack/block_kit/element/image_element.rb +26 -0
- data/lib/slack/block_kit/element/multi_channels_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_conversations_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_external_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_static_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_users_select_element.rb +39 -0
- data/lib/slack/block_kit/element/overflow_element.rb +42 -0
- data/lib/slack/block_kit/element/select_element.rb +45 -0
- data/lib/slack/block_kit/element/static_select_element.rb +46 -0
- data/lib/slack/block_kit/element/users_select_element.rb +24 -0
- data/lib/slack/block_kit/execution_context.rb +64 -0
- data/lib/slack/block_kit/refinements/hash_compact.rb +15 -0
- data/lib/slack/block_kit/type_restricted_array.rb +21 -0
- data/lib/slack/block_kit/version.rb +5 -0
- data/slack-block-kit.gemspec +29 -0
- metadata +166 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class ImageElement < Element
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_accessor :image_url, :alt_text
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
object.image_url = hash.fetch(:image_url)
|
12
|
+
object.alt_text = hash.fetch(:alt_text)
|
13
|
+
|
14
|
+
super(hash, object)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_h
|
18
|
+
super.merge(
|
19
|
+
image_url: image_url,
|
20
|
+
alt_text: alt_text
|
21
|
+
).compact
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class MultiChannelsSelectElement < ChannelsSelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
undef_method :initial_channel=
|
9
|
+
attr_reader :initial_channels, :max_selected_items
|
10
|
+
|
11
|
+
def self.populate(hash, object)
|
12
|
+
hash[:initial_channels].each(&object.initial_channels.method(:<<)) if hash.key?(:initial_channels)
|
13
|
+
object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
|
14
|
+
|
15
|
+
super(hash, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
@initial_channels = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def max_selected_items=(num)
|
24
|
+
raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
|
25
|
+
|
26
|
+
@max_selected_items = num.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
super.merge(
|
31
|
+
initial_channels: initial_channels&.to_h,
|
32
|
+
max_selected_items: max_selected_items || 1
|
33
|
+
).compact
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class MultiConversationsSelectElement < ConversationsSelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
undef_method :initial_conversation=
|
9
|
+
attr_reader :initial_conversations, :max_selected_items
|
10
|
+
|
11
|
+
def self.populate(hash, object)
|
12
|
+
hash[:initial_conversations].each(&object.initial_conversations.method(:<<)) if hash.key?(:initial_conversations)
|
13
|
+
object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
|
14
|
+
|
15
|
+
super(hash, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
@initial_conversations = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def max_selected_items=(num)
|
24
|
+
raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
|
25
|
+
|
26
|
+
@max_selected_items = num.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
super.merge(
|
31
|
+
initial_conversations: initial_conversations&.to_h,
|
32
|
+
max_selected_items: max_selected_items || 1
|
33
|
+
).compact
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class MultiExternalSelectElement < ExternalSelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
undef_method :initial_option=
|
9
|
+
attr_reader :initial_options, :max_selected_items
|
10
|
+
|
11
|
+
def self.populate(hash, object)
|
12
|
+
hash[:initial_options].each(&object.initial_options.method(:<<)) if hash.key?(:initial_options)
|
13
|
+
object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
|
14
|
+
|
15
|
+
super(hash, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
@initial_options = TypeRestrictedArray.new(CompositionObjects::Option)
|
21
|
+
end
|
22
|
+
|
23
|
+
def max_selected_items=(num)
|
24
|
+
raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
|
25
|
+
|
26
|
+
@max_selected_items = num.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
super.merge(
|
31
|
+
initial_options: initial_options&.to_h,
|
32
|
+
max_selected_items: max_selected_items || 1
|
33
|
+
).compact
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class MultiStaticSelectElement < StaticSelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
undef_method :initial_option=
|
9
|
+
attr_reader :initial_options, :max_selected_items
|
10
|
+
|
11
|
+
def self.populate(hash, object)
|
12
|
+
hash[:initial_options].each(&object.initial_options.method(:<<)) if hash.key?(:initial_options)
|
13
|
+
object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
|
14
|
+
|
15
|
+
super(hash, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
@initial_options = TypeRestrictedArray.new(CompositionObjects::Option)
|
21
|
+
end
|
22
|
+
|
23
|
+
def max_selected_items=(num)
|
24
|
+
raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
|
25
|
+
|
26
|
+
@max_selected_items = num.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
super.merge(
|
31
|
+
initial_options: initial_options&.to_h,
|
32
|
+
max_selected_items: max_selected_items || 1
|
33
|
+
).compact
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class MultiUsersSelectElement < UsersSelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
|
9
|
+
undef_method :initial_user=
|
10
|
+
attr_reader :initial_users, :max_selected_items
|
11
|
+
|
12
|
+
def self.populate(hash, object)
|
13
|
+
hash[:initial_users].each(&object.initial_users.method(:<<)) if hash.key?(:initial_users)
|
14
|
+
object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
|
15
|
+
|
16
|
+
super(hash, object)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
super
|
21
|
+
@initial_users = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def max_selected_items=(num)
|
25
|
+
raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
|
26
|
+
|
27
|
+
@max_selected_items = num.to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_h
|
31
|
+
super.merge(
|
32
|
+
initial_users: initial_users&.to_h,
|
33
|
+
max_selected_items: max_selected_items || 1
|
34
|
+
).compact
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class OverflowElement < Element
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :options, :confirm
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
hash[:options].each(&object.options.method(:<<)) if hash.key?(:options)
|
12
|
+
object.confirm = hash.fetch(:confirm) if hash[:confirm]
|
13
|
+
|
14
|
+
super(hash, object)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@options = TypeRestrictedArray.new(CompositionObjects::Option)
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
(2..5).include?(options.size)
|
23
|
+
end
|
24
|
+
|
25
|
+
def confirm=(obj)
|
26
|
+
unless obj.is_a?(CompositionObjects::ConfirmationDialog)
|
27
|
+
raise TypeError, 'confirm must be a ConfirmationDialog Object'
|
28
|
+
end
|
29
|
+
|
30
|
+
@confirm = obj
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_h
|
34
|
+
super.merge(
|
35
|
+
options: options.map(&:to_h),
|
36
|
+
confirm: confirm&.to_h
|
37
|
+
).compact
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class SelectElement < Element
|
7
|
+
attr_reader :placeholder, :confirm
|
8
|
+
|
9
|
+
def self.populate(hash, object)
|
10
|
+
object.placeholder = hash.fetch(:placeholder)
|
11
|
+
object.confirm = hash[:confirm] if hash.key?(:confirm)
|
12
|
+
|
13
|
+
super(hash, object)
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid?
|
17
|
+
!(@placeholder.nil? || @placeholder.empty?)
|
18
|
+
end
|
19
|
+
|
20
|
+
def placeholder=(obj)
|
21
|
+
raise TypeError, 'placeholder must be a Text Object' unless obj.is_a?(CompositionObjects::Text)
|
22
|
+
raise TypeError, 'placeholder must be plain_text' unless obj.type == :plain_text
|
23
|
+
raise RangeError, 'placeholder is max 150 characters' unless obj.text.size <= 150
|
24
|
+
|
25
|
+
@placeholder = obj
|
26
|
+
end
|
27
|
+
|
28
|
+
def confirm=(obj)
|
29
|
+
unless obj.is_a?(CompositionObjects::ConfirmationDialog)
|
30
|
+
raise TypeError, 'confirm must be a ConfirmationDialog Object'
|
31
|
+
end
|
32
|
+
|
33
|
+
@confirm = obj
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_h
|
37
|
+
super.merge(
|
38
|
+
placeholder: placeholder.to_h,
|
39
|
+
confirm: confirm&.to_h
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class StaticSelectElement < SelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :options, :option_groups, :initial_option
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
hash[:options].each(&object.options.method(:<<)) if hash.key?(:options)
|
12
|
+
hash[:option_groups].each(&object.option_groups.method(:<<)) if hash.key?(:option_groups)
|
13
|
+
object.initial_option = hash[:initial_option] if hash.key?(:initial_option)
|
14
|
+
|
15
|
+
super(hash, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@options = TypeRestrictedArray.new(CompositionObjects::Option)
|
20
|
+
@option_groups = TypeRestrictedArray.new(CompositionObjects::OptionGroup)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Either options or option_groups must exist and be non-empty.
|
24
|
+
def valid?
|
25
|
+
if @options.nil? || @options.empty? then !@option_groups.empty?
|
26
|
+
else !@options&.empty?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initial_option=(obj)
|
31
|
+
raise TypeError, 'text must be a Option Object' unless obj.is_a?(CompositionObjects::Option)
|
32
|
+
|
33
|
+
@initial_option = obj
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_h
|
37
|
+
super.merge(
|
38
|
+
options: options.map(&:to_h),
|
39
|
+
option_groups: option_groups.map(&:to_h),
|
40
|
+
initial_option: initial_option&.to_h
|
41
|
+
).compact
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class UsersSelectElement < SelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_accessor :initial_user
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
object.initial_user = hash[:initial_user] if hash.key?(:initial_user)
|
12
|
+
|
13
|
+
super(hash, object)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
super.merge(
|
18
|
+
initial_user: initial_user
|
19
|
+
).compact
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
# TO USE:
|
6
|
+
# include Slack::Messages::Blocks::ExecutionContext
|
7
|
+
# data = [ SectionBlock[text: Text[mrkdwn: 'wheeee']] ]
|
8
|
+
# Slack::Messages::Blocks::ExecutionContext.test(data)
|
9
|
+
# => {
|
10
|
+
# "blocks": [
|
11
|
+
# {
|
12
|
+
# "type": "section",
|
13
|
+
# "text": {
|
14
|
+
# "type": "mrkdwn",
|
15
|
+
# "text": "wheeee"
|
16
|
+
# }
|
17
|
+
# }
|
18
|
+
# ]
|
19
|
+
# }
|
20
|
+
# This can be copied and pasted into https://api.slack.com/tools/block-kit-builder
|
21
|
+
module ExecutionContext
|
22
|
+
ActionsBlock = Block::ActionsBlock
|
23
|
+
ContextBlock = Block::ContextBlock
|
24
|
+
DividerBlock = Block::DividerBlock
|
25
|
+
ImageBlock = Block::ImageBlock
|
26
|
+
SectionBlock = Block::SectionBlock
|
27
|
+
|
28
|
+
def DividerBlock
|
29
|
+
DividerBlock[]
|
30
|
+
end
|
31
|
+
|
32
|
+
ConfirmationDialog = CompositionObjects::ConfirmationDialog
|
33
|
+
Filter = CompositionObjects::Filter
|
34
|
+
Option = CompositionObjects::Option
|
35
|
+
OptionGroup = CompositionObjects::OptionGroup
|
36
|
+
Text = CompositionObjects::Text
|
37
|
+
|
38
|
+
ButtonElement = Element::ButtonElement
|
39
|
+
DatePickerElement = Element::DatePickerElement
|
40
|
+
ImageElement = Element::ImageElement
|
41
|
+
OverflowElement = Element::OverflowElement
|
42
|
+
|
43
|
+
ConversationsSelectElement = Element::ConversationsSelectElement
|
44
|
+
ChannelsSelectElement = Element::ChannelsSelectElement
|
45
|
+
ExternalSelectElement = Element::ExternalSelectElement
|
46
|
+
StaticSelectElement = Element::StaticSelectElement
|
47
|
+
UsersSelectElement = Element::UsersSelectElement
|
48
|
+
|
49
|
+
MultiConversationsSelectElement = Element::MultiConversationsSelectElement
|
50
|
+
MultiChannelsSelectElement = Element::MultiChannelsSelectElement
|
51
|
+
MultiExternalSelectElement = Element::MultiExternalSelectElement
|
52
|
+
MultiStaticSelectElement = Element::MultiStaticSelectElement
|
53
|
+
MultiUsersSelectElement = Element::MultiUsersSelectElement
|
54
|
+
|
55
|
+
Bold = proc { |string| "*#{string}*" }
|
56
|
+
Italic = proc { |string| "_#{string}_" }
|
57
|
+
Strike = proc { |string| "~#{string}~" }
|
58
|
+
Code = proc { |string| "`#{string}`" }
|
59
|
+
Link = proc { |link, label = nil| label.nil? || label.empty? ? link : "<#{link}|#{label}>" }
|
60
|
+
Emoji = proc { |string| ":#{string}:" }
|
61
|
+
CodeBlock = proc { |&block| [ '```', yield, '```' ].join(Text::NEWLINE) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|