Module: Ruflet::UI::ControlFactory
- Defined in:
- lib/ruflet_ui/ruflet/ui/control_factory.rb
Constant Summary collapse
- CLASS_MAP =
Services::RufletServices::CLASS_MAP .merge(Controls::RufletControls::CLASS_MAP) .freeze
- CONSTRUCTOR_KEYWORDS_CACHE =
{}
- PYTHON_COMMON_ATTRIBUTES =
%i[flip ref transform].freeze
- PYTHON_ATTRIBUTE_OVERRIDES =
{ "expansionpanellist" => %i[auto_scroll on_scroll scroll scroll_interval], "fletapp" => %i[assets_dir on_python_output], "image" => %i[ align animate_align animate_margin animate_offset animate_opacity animate_position animate_rotation animate_scale animate_size aspect_ratio badge bottom col disabled expand expand_loose left margin offset on_animation_end on_size_change opacity right rotate rtl scale size_change_interval tooltip top visible ], "navigationrail" => %i[pin_leading_to_top pin_trailing_to_bottom scrollable], "responsiverow" => %i[auto_scroll on_scroll scroll scroll_interval], "text" => %i[ align animate_align animate_margin animate_offset animate_opacity animate_position animate_rotation animate_scale animate_size aspect_ratio badge bottom col disabled expand expand_loose height left margin offset on_animation_end on_size_change opacity right rtl scale size_change_interval tooltip top visible width ] }.freeze
Class Method Summary collapse
- .build(type, id: nil, **props) ⇒ Object
- .constructor_keywords(klass) ⇒ Object
- .normalize_common_value(value) ⇒ Object
- .normalize_constructor_props(klass, type, props) ⇒ Object
Class Method Details
.build(type, id: nil, **props) ⇒ Object
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 63 |
# File 'lib/ruflet_ui/ruflet/ui/control_factory.rb', line 38 def build(type, id: nil, **props) normalized_type = type.to_s.downcase if ENV["RUFLET_DEBUG"] == "1" && normalized_type == "floatingactionbutton" Kernel.warn("[factory] type=#{normalized_type} id=#{id.inspect} props=#{props.inspect}") end klass = CLASS_MAP[normalized_type] if klass normalized_props, supplemental_props = normalize_constructor_props(klass, normalized_type, props) if ENV["RUFLET_DEBUG"] == "1" && normalized_type == "floatingactionbutton" Kernel.warn("[factory] normalized_props=#{normalized_props.inspect}") end control = klass.new(id: id, **normalized_props) supplemental_props.each do |key, value| if key.to_s.start_with?("on_") && value.respond_to?(:call) control.attach_handler(key.to_s.delete_prefix("on_"), value) next end next if key == :ref control.props[key.to_s] = normalize_common_value(value) end return control end Control.new(type: normalized_type, id: id, **props) end |
.constructor_keywords(klass) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/ruflet_ui/ruflet/ui/control_factory.rb', line 82 def constructor_keywords(klass) return CONSTRUCTOR_KEYWORDS_CACHE[klass] if CONSTRUCTOR_KEYWORDS_CACHE.key?(klass) keywords = if klass.const_defined?(:KEYWORDS) klass::KEYWORDS else klass.instance_method(:initialize).parameters .select { |kind, _| kind == :key || kind == :keyreq } .map { |_, name| name } .reject { |name| name == :id } end CONSTRUCTOR_KEYWORDS_CACHE[klass] = keywords.freeze rescue StandardError [] end |
.normalize_common_value(value) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/ruflet_ui/ruflet/ui/control_factory.rb', line 99 def normalize_common_value(value) case value when Hash value.each_with_object({}) do |(key, nested), result| result[key.to_s] = normalize_common_value(nested) end when Array value.map { |nested| normalize_common_value(nested) } when Symbol value.to_s else value end end |
.normalize_constructor_props(klass, type, props) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/ruflet_ui/ruflet/ui/control_factory.rb', line 65 def normalize_constructor_props(klass, type, props) keywords = constructor_keywords(klass) return [props, {}] if keywords.empty? && PYTHON_ATTRIBUTE_OVERRIDES[type].nil? allowed = keywords.map(&:to_s) mapped = props.each_with_object({}) { |(k, v), out| out[k.to_sym] = v } if mapped.key?("value") && !allowed.include?("value") && allowed.include?("text") && !mapped.key?("text") mapped["text"] = mapped.delete("value") end if mapped.key?(:value) && !allowed.include?("value") && allowed.include?("text") && !mapped.key?(:text) mapped[:text] = mapped.delete(:value) end supplemental_names = PYTHON_COMMON_ATTRIBUTES + PYTHON_ATTRIBUTE_OVERRIDES.fetch(type, []) supplemental = mapped.slice(*supplemental_names) [mapped.reject { |key, _| supplemental_names.include?(key) }, supplemental] end |