Sitelet https://github.com/jruby/jruby/issues/8428
Skip to content

Oddity (for me), just reporting it: NameError: no method 'add' for arguments (javax.swing.JButton,java.awt.GridBagConstraints,org.jruby.RubyProc) on Java::JavaxSwing::JPanel #8428

Description

@rubyFeedback

Today I ran into an (to me) interesting error.

The error was this:

NameError: no method 'add' for arguments (javax.swing.JButton,java.awt.GridBagConstraints,org.jruby.RubyProc) on Java::JavaxSwing::JPanel

.add() is a typical method for container-widgets in java-swing/jruby-swing - or
rather, in general. I think ruby-gtk3 also has an .add() method for most of the
container-widgets.

Now the method call I was using was using three arguments:

add(
  widget,
  grid_bag_constraints,
  &block
)

First argument, widget, would be for JPanel in my case.

grid_bag_constraints was my wrapper over GridBagConstraints, in the hope of
using less code.

&block was just a dump of the "primary" block being passed.

The method was similar to the following one, on class JPanel:

# ========================================================================== #
# === add_complex
# ========================================================================== #
def add_complex(
    widget,
    grid_bag_constraints = new_grid_bag_constraints,
    &block
  )
  case grid_bag_constraints
  # ======================================================================== #
  # === :nil
  # ======================================================================== #
  when :nil, nil
    grid_bag_constraints = new_grid_bag_constraints
  end
  # ======================================================================== #
  # === Handle blocks given to this method next
  # ======================================================================== #
  if block_given?
    yielded = yield
    if yielded.is_a?(Hash)
      # ==================================================================== #
      # === :x
      # ==================================================================== #
      if yielded.has_key? :x
        grid_bag_constraints.gridx = yielded.delete(:x)
      end
      # ==================================================================== #
      # === :y
      # ==================================================================== #
      if yielded.has_key? :y
        grid_bag_constraints.gridy = yielded.delete(:y)
      end
      # ==================================================================== #
      # === :gridwidth
      # ==================================================================== #
      if yielded.has_key? :gridwidth
        grid_bag_constraints.gridwidth = yielded.delete(:gridwidth)
      # ==================================================================== #
      # === :span_row
      # ==================================================================== #
      elsif yielded.has_key? :span_row
        grid_bag_constraints.gridwidth = yielded.delete(:span_row)
      end
      # ==================================================================== #
      # === :gridheight
      # ==================================================================== #
      if yielded.has_key? :gridheight
        grid_bag_constraints.gridheight = yielded.delete(:gridheight)
      end
      # ==================================================================== #
      # === :insets
      # ==================================================================== #
      if yielded.has_key? :insets
        value = yielded.delete(:insets)
        grid_bag_constraints.insets = Insets.new(value, value, value, value)
      end
      # ==================================================================== #
      # === :fill
      #
      # The :fill argument is usually
      # java.awt.GridBagConstraints::HORIZONTAL. HORIZONTAL is an Integer,
      # with a value of 2.
      # ==================================================================== #
      if yielded.has_key? :fill
        fill_value = yielded.delete(:fill)
        case fill_value
        # ================================================================== #
        # === :both
        # ================================================================== #
        when :both
          fill_value = java.awt.GridBagConstraints::BOTH
        # ================================================================== #
        # === :horizontal
        # ================================================================== #
        when :horizontal
          fill_value = java.awt.GridBagConstraints::HORIZONTAL
        # ================================================================== #
        # === :vertical
        # ================================================================== #
        when :vertical
          fill_value = java.awt.GridBagConstraints::VERTICAL
        end
        grid_bag_constraints.fill = fill_value
      end
    end
  end
  add(
    widget,
    grid_bag_constraints,
    &block
  )
end

The faulty part is the last &block. I removed it and the method works fine now,
but ... I was wondering about it nonetheless. Granted, I handle the block
arguments within the method itself, for java.awt.GridBagConstraints, so I don't
need to pass it into the method .add(). However had, isn't the error message
kind of strange?

I believe in MRI ruby, such an error would not be raised; the second &block
within the add() call would just be ignored silently, I think. In jruby it
seems as if it is a specific instance of a class called org.jruby.RubyProc,
and this is then checked against various signature methods (I think?).

Java Swing .add() has several invocation ways:

https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/javax/swing/JPanel.html

So I somewhat understand that jruby has to remain flexible here - I understand
that constraint. Still, it was a bit peculiar to me that this would yield
an error. Again, I can kind of understand it, but it was peculiar to see.

I am not really saying anything has to be changed, mind you, so I'll close
this issue, but it is another small oddity, so the purpose of this here is
primarily to point it out. It seems there are some slight differences between
jruby and MRI ruby and newcomers to jruby may not know all of these differences
initially (I am still finding them, probably in the future as well, I suppose).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions