block-kit 1.0.0 → 1.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e870bbe818fc81700e8112f99de5ddad4c27340d6e0cebc89d536f63e2a90123
4
- data.tar.gz: 786f5df43117cf99fdcdf5a31886a5618bd5f19a6c360978906c6aa24033d32d
3
+ metadata.gz: b66e1897645e7673dc805967bf49b12ac5e122df9dd36d6bdc1eac77934eaf0d
4
+ data.tar.gz: cbbfa5ba5211f551c8fb614f734b5591fd6b2623ac9a3b40c515999778fdc9db
5
5
  SHA512:
6
- metadata.gz: 551382789b7591dd7041236cc4504d8defe7e94b087ed7107eae2f3c77520bb7e92360256e2f9d597bf133c864d47b361b479d28cf153e6b415034b5275df08c
7
- data.tar.gz: 854d019c85780c5242915319bf86a583b74c8f6ea0fc3aaa2dae2315255c36fe0ec0c86edcd85cbbcd564b5540a9e5504215ce4ea7126ea33d202cc7a1f0933d
6
+ metadata.gz: 3f3814f0b9701db69348f0437189fa92e86f7104f9748cb3bb276f20febbffb3d5ce3dff0b60bc800ba2ebd7ae1241963a18079092f1b3ece394e3282abe192a
7
+ data.tar.gz: 402c7b4b27743fb33a1e9241f6a310578cd2ad712be33551212caf98f4b01fa3d589732988e761e16409467aad4df6612371e64e7c7374b4d3716e64a7cba3f2
data/README.md CHANGED
@@ -18,7 +18,7 @@ gem install block-kit
18
18
 
19
19
  ## Usage
20
20
 
21
- Blocks can be built individually or as a surface or collection of blocks, which each block able to initialize with a simple Hash or attributes or via a block-based DSL. For example, each of the following declarations would result in the same `section` block:
21
+ Blocks can be built individually or as a surface or collection of blocks, which each block able to initialize with a simple Hash of attributes or via a block-based DSL. For example, each of the following declarations would result in the same `section` block:
22
22
 
23
23
  ```ruby
24
24
  require "block-kit"
@@ -180,4 +180,8 @@ The gem is available as open source under the terms of the [MIT License](https:/
180
180
 
181
181
  ## Code of Conduct
182
182
 
183
- Everyone interacting in the Block::Kit project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/davidcelis/block-kit/blob/main/CODE_OF_CONDUCT.md).
183
+ Everyone interacting in the project's codebase, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/davidcelis/block-kit/blob/main/CODE_OF_CONDUCT.md).
184
+
185
+ ## Acknowledgements
186
+
187
+ Special thanks to [FireHydrant](https://firehydrant.com) for allowing me to build the initial version on the job (and therefore sponsoring the project)!
data/lib/block-kit.rb ADDED
@@ -0,0 +1 @@
1
+ require_relative "block_kit"
@@ -29,8 +29,8 @@ module BlockKit
29
29
  attribute_fixers[:base] << {name: method_name, dangerous: dangerous}
30
30
  end
31
31
 
32
- def self.inherited(base)
33
- base.attribute_fixers = attribute_fixers.dup
32
+ def self.inherited(subclass)
33
+ subclass.attribute_fixers = attribute_fixers.deep_dup
34
34
  end
35
35
 
36
36
  def initialize(attributes = {})
@@ -25,6 +25,10 @@ module BlockKit
25
25
  validates :description, presence: true, length: {maximum: MAX_DESCRIPTION_LENGTH}, allow_nil: true
26
26
  fixes :description, truncate: {maximum: MAX_DESCRIPTION_LENGTH}, null_value: [:blank]
27
27
 
28
+ def self.inherited(subclass)
29
+ subclass.attribute_fixers = attribute_fixers.deep_dup
30
+ end
31
+
28
32
  def initial?
29
33
  !!initial
30
34
  end
@@ -11,6 +11,10 @@ module BlockKit
11
11
 
12
12
  delegate :blank?, :present?, to: :text
13
13
 
14
+ def self.inherited(subclass)
15
+ subclass.attribute_fixers = attribute_fixers.deep_dup
16
+ end
17
+
14
18
  def length
15
19
  text&.length || 0
16
20
  end
@@ -9,6 +9,10 @@ module BlockKit
9
9
  validates :action_id, presence: true, length: {maximum: MAX_ACTION_ID_LENGTH}, allow_nil: true
10
10
  fixes :action_id, truncate: {maximum: MAX_ACTION_ID_LENGTH, dangerous: true, omission: ""}, null_value: {error_types: [:blank]}
11
11
 
12
+ def self.inherited(subclass)
13
+ subclass.attribute_fixers = attribute_fixers.deep_dup
14
+ end
15
+
12
16
  def initialize(attributes = {})
13
17
  raise NotImplementedError, "#{self.class} is an abstract class and can't be instantiated." if instance_of?(Base)
14
18
 
@@ -27,6 +27,10 @@ module BlockKit
27
27
  validates :accessibility_label, presence: true, length: {maximum: MAX_ACCESSIBILITY_LABEL_LENGTH}, allow_nil: true
28
28
  fixes :accessibility_label, truncate: {maximum: MAX_ACCESSIBILITY_LABEL_LENGTH}, null_value: {error_types: [:blank]}
29
29
 
30
+ def self.inherited(subclass)
31
+ subclass.attribute_fixers = attribute_fixers.deep_dup
32
+ end
33
+
30
34
  def initialize(attributes = {})
31
35
  raise NotImplementedError, "#{self.class} is an abstract class and can't be instantiated." if instance_of?(BaseButton)
32
36
 
@@ -7,6 +7,10 @@ module BlockKit
7
7
  validates :max_selected_items, presence: true, numericality: {only_integer: true, greater_than: 0}, allow_nil: true
8
8
  fixes :max_selected_items, null_value: {error_types: [:greater_than]}
9
9
 
10
+ def self.inherited(subclass)
11
+ subclass.attribute_fixers = attribute_fixers.deep_dup
12
+ end
13
+
10
14
  def initialize(attributes = {})
11
15
  raise NotImplementedError, "#{self.class} is an abstract class and can't be instantiated." if instance_of?(MultiSelect)
12
16
 
@@ -8,6 +8,10 @@ module BlockKit
8
8
  include Concerns::HasPlaceholder
9
9
  include Concerns::PlainTextEmojiAssignment.new(:placeholder)
10
10
 
11
+ def self.inherited(subclass)
12
+ subclass.attribute_fixers = attribute_fixers.deep_dup
13
+ end
14
+
11
15
  def initialize(attributes = {})
12
16
  raise NotImplementedError, "#{self.class} is an abstract class and can't be instantiated." if instance_of?(Select)
13
17
 
@@ -9,6 +9,10 @@ module BlockKit
9
9
  validates :block_id, presence: true, length: {maximum: MAX_BLOCK_ID_LENGTH}, allow_nil: true
10
10
  fixes :block_id, truncate: {maximum: MAX_BLOCK_ID_LENGTH, dangerous: true, omission: ""}, null_value: {error_types: [:blank]}
11
11
 
12
+ def self.inherited(subclass)
13
+ subclass.attribute_fixers = attribute_fixers.deep_dup
14
+ end
15
+
12
16
  def initialize(attributes = {})
13
17
  raise NotImplementedError, "#{self.class} is an abstract class and can't be instantiated." if instance_of?(Base)
14
18
 
@@ -45,6 +45,10 @@ module BlockKit
45
45
  dsl_method :blocks, as: :section, type: Layout::Section
46
46
  dsl_method :blocks, as: :video, type: Layout::Video, required_fields: [:alt_text, :title, :thumbnail_url, :video_url], yields: false
47
47
 
48
+ def self.inherited(subclass)
49
+ subclass.attribute_fixers = attribute_fixers.deep_dup
50
+ end
51
+
48
52
  def initialize(attributes = {})
49
53
  raise NotImplementedError, "#{self.class} is an abstract class and can't be instantiated." if instance_of?(Base)
50
54
 
@@ -50,7 +50,9 @@ module BlockKit
50
50
  fixes :close, truncate: {maximum: MAX_BUTTON_LENGTH}, null_value: {error_types: [:blank]}
51
51
 
52
52
  validates :submit, presence: true, length: {maximum: MAX_BUTTON_LENGTH}, allow_nil: true
53
+ validate :submit_present_if_contains_input
53
54
  fixes :submit, truncate: {maximum: MAX_BUTTON_LENGTH}, null_value: {error_types: [:blank]}
55
+ fix :add_default_submit_button
54
56
 
55
57
  def initialize(attributes = {})
56
58
  attributes = attributes.with_indifferent_access
@@ -69,6 +71,20 @@ module BlockKit
69
71
  submit_disabled: submit_disabled
70
72
  ).compact
71
73
  end
74
+
75
+ private
76
+
77
+ def submit_present_if_contains_input
78
+ errors.add(:submit, "can't be blank when blocks contain input elements") if contains_input? && submit.blank?
79
+ end
80
+
81
+ def add_default_submit_button
82
+ self.submit = "Submit" if contains_input? && submit.blank?
83
+ end
84
+
85
+ def contains_input?
86
+ blocks.any? { |block| block.is_a?(Layout::Input) }
87
+ end
72
88
  end
73
89
  end
74
90
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BlockKit
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.2"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: block-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Celis
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2025-04-21 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activemodel
@@ -50,6 +50,7 @@ files:
50
50
  - LICENSE.txt
51
51
  - README.md
52
52
  - Rakefile
53
+ - lib/block-kit.rb
53
54
  - lib/block_kit.rb
54
55
  - lib/block_kit/base.rb
55
56
  - lib/block_kit/blocks.rb
@@ -71,7 +72,6 @@ files:
71
72
  - lib/block_kit/concerns/confirmable.rb
72
73
  - lib/block_kit/concerns/conversation_selection.rb
73
74
  - lib/block_kit/concerns/dispatchable.rb
74
- - lib/block_kit/concerns/dsl_generation.rb
75
75
  - lib/block_kit/concerns/external.rb
76
76
  - lib/block_kit/concerns/focusable_on_load.rb
77
77
  - lib/block_kit/concerns/has_initial_option.rb
@@ -184,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
184
  - !ruby/object:Gem::Version
185
185
  version: '0'
186
186
  requirements: []
187
- rubygems_version: 3.6.7
187
+ rubygems_version: 3.6.6
188
188
  specification_version: 4
189
189
  summary: A powerful DSL-based library for Slack's Block Kit framework.
190
190
  test_files: []
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BlockKit
4
- module Concerns
5
- module DSLGeneration
6
- extend ActiveSupport::Concern
7
-
8
- class_methods do
9
- private
10
-
11
- def dsl_method(attribute, as: nil, type: nil, required_fields: [], mutually_exclusive_fields: [], yields: true)
12
- type ||= attribute_types[attribute.to_s]
13
- type = Types::Generic.of_type(type) if type.is_a?(Class) && type < BlockKit::Base
14
- raise ArgumentError, "attribute #{attribute} does not exist" if type.instance_of?(ActiveModel::Type::Value)
15
-
16
- is_array_attribute = false
17
-
18
- if type.instance_of?(Types::Array)
19
- is_array_attribute = true
20
- type = type.item_type
21
- end
22
-
23
- is_array_attribute ||= attribute_types[attribute.to_s].type == :array
24
-
25
- fields = type.block_class.attribute_names.map(&:to_sym)
26
- plain_text_fields = type.block_class.attribute_types.select { |_, v| v.respond_to?(:block_class) && v.block_class == Composition::PlainText }.keys.map(&:to_sym)
27
-
28
- define_method(as || attribute) do |args = {}, &block|
29
- args = args.symbolize_keys
30
-
31
- # Return the existing attribute if no args or block are passed and we're not in a custom-named method
32
- return super() if args.blank? && block.nil? && as.nil?
33
-
34
- if (missing_required_fields = (required_fields - args.keys)) && missing_required_fields.any?
35
- message = "missing keyword#{"s" if missing_required_fields.size > 1}: #{missing_required_fields.map(&:inspect).join(", ")}"
36
- raise ArgumentError, message
37
- end
38
-
39
- unknown_fields = (args.keys - fields)
40
- unknown_fields.delete(:emoji) if plain_text_fields.any?
41
-
42
- if unknown_fields.any?
43
- message = "unknown keyword#{"s" if unknown_fields.size > 1}: #{unknown_fields.map(&:inspect).join(", ")}"
44
- raise ArgumentError, message
45
- end
46
-
47
- mutually_exclusive = mutually_exclusive_fields & args.keys
48
- if mutually_exclusive.length > 1
49
- message = "mutually exclusive keywords: #{mutually_exclusive.map(&:inspect).join(", ")}"
50
- raise ArgumentError, message
51
- end
52
-
53
- new_value = if is_array_attribute
54
- public_send(:"#{attribute}=", []) if public_send(attribute).nil?
55
- public_send(attribute) << type.cast(args)
56
- public_send(attribute).last
57
- else
58
- public_send(:"#{attribute}=", type.cast(args))
59
- public_send(attribute)
60
- end
61
-
62
- plain_text_fields.each do |field|
63
- next unless args.key?(field)
64
-
65
- new_value.public_send(field).emoji = args[:emoji] if args.key?(:emoji)
66
- end
67
-
68
- block&.call(new_value) if yields
69
-
70
- self
71
- end
72
- end
73
- end
74
- end
75
- end
76
- end