profligacy 0.4.1-jruby → 1.0-jruby

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.
data/README CHANGED
@@ -8,10 +8,6 @@ The project is hosted at:
8
8
 
9
9
  Where you can file bugs and other things, as well as download gems manually.
10
10
 
11
- == Motivation
12
-
13
- == Installing
14
-
15
11
  == License
16
12
 
17
13
  See the COPYING file included with the source. It's the same license as Ruby but
@@ -19,4 +15,5 @@ Copyright Zed A. Shaw 2007 All Right Reserved.
19
15
 
20
16
  == Source Code
21
17
 
22
- Source is available from the ihate project page.
18
+ Source is available from the ihate project page in the Files section as a .tgz
19
+ source tarball.
data/Rakefile CHANGED
@@ -13,9 +13,9 @@ setup_clean ["pkg", "lib/*.bundle", "lib/profligacy/*.class", "*.gem", ".config"
13
13
  setup_rdoc ['README', 'LICENSE', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc']
14
14
 
15
15
  desc "Does a full compile, test run"
16
- task :default => [:ragel, :test]
16
+ task :default => ["lib/profligacy/parser.jar", :test]
17
17
 
18
- version="0.4.1"
18
+ version="1.0"
19
19
  name="profligacy"
20
20
 
21
21
  setup_gem(name, version) do |spec|
@@ -30,9 +30,15 @@ setup_gem(name, version) do |spec|
30
30
  spec.platform = "jruby"
31
31
  end
32
32
 
33
- task :ragel do
33
+ file "lib/profligacy/LELParser.java" => ["lib/profligacy/LELParser.rl"] do
34
34
  sh %{/usr/local/bin/ragel -J lib/profligacy/LELParser.rl | /usr/local/bin/rlgen-java -o lib/profligacy/LELParser.java}
35
+ end
36
+
37
+ file "lib/profligacy/LELParser.class" => ["lib/profligacy/LELParser.java"] do
35
38
  sh %{javac -target 1.5 lib/profligacy/LELParser.java}
39
+ end
40
+
41
+ file "lib/profligacy/parser.jar" => ["lib/profligacy/LELParser.class"] do
36
42
  Dir.chdir("lib") do
37
43
  sh %{jar -cf profligacy/parser.jar profligacy/*.class}
38
44
  end
@@ -51,4 +57,4 @@ task :site do
51
57
  sh %{rsync -av doc/rdoc doc/site/output/* rubyforge.org:/var/www/gforge-projects/ihate/profligacy}
52
58
  end
53
59
 
54
- task :project => [:clean, :ragel, :default, :test, :rdoc, :package, :site]
60
+ task :project => [:clean, :default, :test, :rdoc, :package, :site]
@@ -1,4 +1,3 @@
1
- require 'profligacy/swing'
2
1
  require 'profligacy/lel'
3
2
 
4
3
  module Test
@@ -9,7 +9,6 @@ require 'profligacy/lel'
9
9
  class ChatInterface
10
10
  include_package 'javax.swing'
11
11
  include_package 'java.awt'
12
-
13
12
  include Profligacy
14
13
 
15
14
  def initialize
@@ -110,4 +109,5 @@ class ChatInterface
110
109
  end
111
110
  end
112
111
 
113
- ChatInterface.new
112
+
113
+ SwingUtilities.invoke_later proc { ChatInterface.new }.to_runnable
@@ -1,9 +1,14 @@
1
+ require 'profligacy/swing'
1
2
  require 'profligacy/parser'
2
3
  require 'profligacy/swing-layout'
3
4
 
4
5
  module Profligacy
5
6
  include_package 'profligacy'
6
7
 
8
+ # This is passed to the parser to scan over the LEL expression
9
+ # initially and pull out the list of cell names that are going
10
+ # to be used. The result of this scan is then used to create
11
+ # the contents and interactions structs.
7
12
  class LELNameScanner
8
13
  include Profligacy::LELParser::LELEventListener
9
14
  attr_reader :children
@@ -21,12 +26,16 @@ module Profligacy
21
26
  end
22
27
  end
23
28
 
29
+ # Used by Swing::Build as the listener for LELParser which configures
30
+ # a GroupLayout from the LEL expression. See http://ihate.rubyforge.org/profligacy/lel.html
31
+ # for instructions on how to use LEL.
24
32
  class LELGroupLayout
25
33
  include Profligacy::LELParser::LELEventListener
26
34
 
27
35
  include_package 'org.jdesktop.layout'
28
36
  include_class 'java.lang.Short'
29
37
 
38
+ # Takes a GroupLayout and the list of components to organize inside it.
30
39
  def initialize(layout, components)
31
40
  @layout = layout
32
41
  @hgroup = @layout.createSequentialGroup
@@ -41,15 +50,18 @@ module Profligacy
41
50
  horizontals_reset
42
51
  end
43
52
 
53
+ # Called when a '|' token is hit by the LELParser.
44
54
  def col
45
55
  horizontals_push; alignments_reset ; widths_reset
46
56
  end
47
57
 
58
+ # Called when a '[' token is hit by the LELParser.
48
59
  def ltab
49
60
  horizontals_reset
50
61
  @vertical = @layout.createBaselineGroup(true, false)
51
62
  end
52
63
 
64
+ # Called when a '^' or '.' token is hit by the LELParser.
53
65
  def valign(dir)
54
66
  case dir
55
67
  when "^" then @valign = GroupLayout::LEADING
@@ -59,6 +71,7 @@ module Profligacy
59
71
  end
60
72
  end
61
73
 
74
+ # Called when a name/id for a cell token is hit by the LELParser.
62
75
  def id(name)
63
76
  h = horizontals_cur
64
77
  component = @components[name]
@@ -71,11 +84,13 @@ module Profligacy
71
84
  end
72
85
  end
73
86
 
87
+ # Called when a ']' token is hit by the LELParser.
74
88
  def row
75
89
  @vgroup.add(@vertical);
76
90
  alignments_reset ; widths_reset ; heights_reset
77
91
  end
78
92
 
93
+ # Called when a '>' or '<' token is hit by the LELParser.
79
94
  def align(direction)
80
95
  case direction
81
96
  when "<" then @halign = GroupLayout::LEADING
@@ -85,18 +100,22 @@ module Profligacy
85
100
  end
86
101
  end
87
102
 
103
+ # Called when a '(#)' is hit (with # being some number) by the LELParser.
88
104
  def setwidth(width)
89
105
  @width = width
90
106
  end
91
107
 
108
+ # Called when a height is added to '(#,#)' expressions in the LELParser.
92
109
  def setheight(height)
93
110
  @height = height
94
111
  end
95
112
 
113
+ # Called when the cell should expand via a '*' token.
96
114
  def expand
97
115
  @max = Short::MAX_VALUE
98
116
  end
99
117
 
118
+ # Called when it's done parsing, and whether there was an error.
100
119
  def finished(error)
101
120
  if !error
102
121
  @layout.setHorizontalGroup(@hgroup);
@@ -106,28 +125,39 @@ module Profligacy
106
125
 
107
126
  private
108
127
 
128
+ # Resets the vertical and horizontal alignments when the end of a or row is
129
+ # passed.
109
130
  def alignments_reset
110
131
  @valign = GroupLayout::CENTER
111
132
  @halign = GroupLayout::CENTER
112
133
  end
113
134
 
135
+ # Same as alignments_reset but for the widths.
114
136
  def widths_reset
115
137
  @width = GroupLayout::DEFAULT_SIZE
116
138
  @max = GroupLayout::DEFAULT_SIZE
117
139
  end
118
140
 
141
+ # Resets the heights when the current row ends.
119
142
  def heights_reset
120
143
  @height = GroupLayout::DEFAULT_SIZE
121
144
  end
122
145
 
146
+ # The horizontal cells are organized in a dynamic array that's expanded as
147
+ # more are encountered. Just like an old typewriter, when the current row
148
+ # ends the next column to work on is "reset" by starting at the first one.
149
+ # This method just resets it to be the next one.
123
150
  def horizontals_reset
124
151
  @htop = 0
125
152
  end
126
153
 
154
+ # Adds a new horizontal cell onto the list of cells being worked on.
127
155
  def horizontals_push
128
156
  @htop += 1
129
157
  end
130
158
 
159
+ # Either makes a new horizontal cell for the curent operation to work on,
160
+ # or just returns the existing one.
131
161
  def horizontals_cur
132
162
  if !@horizontals[@htop]
133
163
  @horizontals[@htop] = @layout.createParallelGroup()
@@ -141,12 +171,29 @@ module Profligacy
141
171
 
142
172
 
143
173
  module Swing
174
+
175
+ # Layout Expression Language is a small regex like wiki language used to
176
+ # specify complex layouts in a tiny amount of space. The language is based on
177
+ # a Ragel based parser that configures a Swing GroupLayout with the right
178
+ # options to produce the desired effect. An example of LEL is:
179
+ #
180
+ #
181
+ # @layout = "
182
+ # [ label_1 | label3 ]
183
+ # [ (300,300)*text1 | (150)people ]
184
+ # [ <label2 | _ ]
185
+ # [ .message | ^buttons ]"
186
+ #
187
+ # Which will produce a panel where you can place components. Otherwise it works
188
+ # exactly like Swing::Build except you pass the LEL expression in to the constructor
189
+ # instead of an array of symbols.
190
+ #
191
+ # See http://ihate.rubyforge.org/profligacy/lel.html for more instructions.
144
192
  class LEL < Build
145
193
  include_package 'org.jdesktop.layout'
146
194
  attr_reader :prefs
147
195
 
148
196
  def initialize(type, expr)
149
-
150
197
  @expr = expr
151
198
  @container_class = type
152
199
  @parser = LELParser.new
@@ -196,6 +243,5 @@ module Profligacy
196
243
  end
197
244
  end
198
245
  end
199
-
200
246
  end
201
247
  end
Binary file
@@ -2,14 +2,43 @@ require 'java'
2
2
 
3
3
  import 'javax.swing.SwingUtilities'
4
4
 
5
- module Profligacy
5
+
6
+ # Profligacy is a library that helps to build Swing GUIs without getting the
7
+ # way of the huge number of components and options available. The approach
8
+ # taken by Profligacy is to be a purposefully leaky abstraction. Rather than
9
+ # try to cover all the possible configurable options available to Swing, it
10
+ # simply attempts to solve three problems:
11
+ #
12
+ # First, building a swing interface involves mixing the layout construction with the
13
+ # widget construction. This is solved by a few simple builders named
14
+ # Swing::Build and Swing::LEL that help organize your components inside a
15
+ # given layout in a way that looks like Ruby and reduces tons of complexity.
16
+ #
17
+ # Second, using any of the more complex layouts like GridBagLayout or GroupLayout is
18
+ # nasty. This is solved by the Layout Expression Language that uses a wiki syntax
19
+ # that matches like a regex and builds any configurable GroupLayout you might need.
20
+ # It removes an *insane* amount of code you'd need to write by hand or the need for
21
+ # an external tool to configure the layout.
22
+ #
23
+ # Writing Java callback Listeners and Runnables is a pain in the ass. This is
24
+ # solved by an ugly hack where Profligacy generates a bunch of Listener -> Proc
25
+ # converters for each of the bazillion Listener implementations that SWing loves
26
+ # even though they all do the same damn thing anyway.
27
+ #
28
+ # See http://ihate.rubyforge.org/profligacy/ for more information.
29
+ #
30
+ module Profligacy
6
31
  module Swing
7
32
  include_class 'java.lang.Runnable'
8
33
  include_package 'java.awt.event'
9
34
  include_package 'javax.swing.event'
10
- include_package 'javax.swing'
35
+ include_package 'javax.swing'
11
36
  include_package 'java.awt'
12
37
 
38
+ # This is used by the added Proc.to_runnable to make a Runnable
39
+ # interface that just calls a proc anyway. With this you can
40
+ # do proc { puts "hi" }.to_runnable and pass the result to
41
+ # threads and such.
13
42
  class RunnableProc
14
43
  include Runnable
15
44
  def initialize(&block)
@@ -22,6 +51,8 @@ module Profligacy
22
51
  end
23
52
 
24
53
 
54
+ # NOTHING TO SEE HERE. GO AWAY. THIS CODE IS WRONG WRONG WRONG
55
+ # AND WILL GO AWAY IN THE NEAR FUTURE.
25
56
  module Listeners
26
57
  AWT_LISTENERS = ["Action","Adjustment","AWTEvent","Component","Container","Focus",
27
58
  "HierarchyBounds","Hierarchy","InputMethod","Item","Key","Mouse",
@@ -36,24 +67,28 @@ module Profligacy
36
67
  "UndoableEdit", ]
37
68
 
38
69
  horrid_java_sucks_ass_hack = (SWING_LISTENERS + AWT_LISTENERS).collect do |listener|
39
- <<-END
40
- class #{listener}ListenerProc
41
- include Profligacy::Swing::#{listener}Listener
70
+ "class #{listener}ListenerProc
71
+ include Profligacy::Swing::#{listener}Listener
42
72
 
43
- def initialize(&block)
44
- @block = block
45
- end
73
+ def initialize(&block)
74
+ @block = block
75
+ end
46
76
 
47
- def method_missing(symb, *args)
48
- @block.call(symb, *args)
49
- end
50
- end
51
- END
77
+ def method_missing(symb, *args)
78
+ @block.call(symb, *args)
79
+ end
80
+ end"
52
81
  end
53
82
 
54
83
  module_eval horrid_java_sucks_ass_hack.join("\n")
55
84
  end
56
85
 
86
+ # The Swing::Build class doesn't actually do any swing stuff, but instead
87
+ # it organizes the common pattern of constructing components, attaching
88
+ # interaction procs or methods.
89
+ #
90
+ # See the many examples and instructions at http://ihate.rubyforge.org/profligacy/
91
+ # for more information.
57
92
  class Build
58
93
  attr_accessor :children
59
94
  attr_accessor :contents
@@ -63,16 +98,40 @@ module Profligacy
63
98
 
64
99
  include_package 'javax.swing'
65
100
 
101
+ # When you construct a Swing::Build you pass in the container
102
+ # to use as the first argument, and then symbols for the names
103
+ # of the contents as the rest of the arguments.
104
+ #
105
+ # ui = Swing::Build.new JFrame, :left, :right, :top do |c,i|
106
+ # ...
107
+ # end
108
+ #
109
+ # The Build class doesn't actually do anything with this until
110
+ # you call the Swing::Build.build method. It just collects up
111
+ # the contents and interactions you attach to the c and i parameters
112
+ # in the block.
113
+ #
114
+ # The c and i parameters stand for contents and interactions and are
115
+ # a Ruby Struct objects that have the names you gave as elements.
116
+ # This means if you try to set one that doesn't exist you'll get an
117
+ # error (which is pretty handy).
66
118
  def initialize(*children)
67
119
  @container_class = children.shift
68
120
  setup_children_and_interactions(children)
69
121
  yield @contents, @interactions
70
122
  end
71
123
 
72
- def interactions
73
- yield @contents, @interactions
74
- end
75
-
124
+ # Build will finally build the container you configured, passing any
125
+ # arguments to that container. When it's done it returns the resulting
126
+ # container for you to modify.
127
+ #
128
+ # You can also attach a block to the method call that will be called
129
+ # with the container right before it's completed. This lets you modify
130
+ # it at the right moment. For example, if you need to set some options
131
+ # to a JFrame right before it's made visible.
132
+ #
133
+ # Finally, it's so common to make containers visible and pack them that
134
+ # this method will do that if the container has those methods.
76
135
  def build(*args)
77
136
  # create the container they ask for with these args
78
137
  @container = @container_class.new *args
@@ -102,6 +161,11 @@ module Profligacy
102
161
  @container
103
162
  end
104
163
 
164
+ # It's kind of a pain to always access ui.contents.thename so
165
+ # the method_missing simply lets you do ui.thename. Won't work
166
+ # of course if your component is named "build", "children",
167
+ # "contents", "interactions", "layout", "container" since those
168
+ # exist in the Build object already.
105
169
  def method_missing(symb, *args)
106
170
  @contents[symb]
107
171
  end
@@ -135,16 +199,27 @@ module Profligacy
135
199
  } if actions
136
200
  end
137
201
  end
202
+
203
+
138
204
  end
139
205
  end
140
206
 
207
+ # Modifications to Proc to make the Runnable and Listener conversion easy.
141
208
  class Proc
209
+ # Takes this proc and converts it to an ListenerProc based on the action name.
210
+ # The name should be one in Profligacy::Listeners and is based on the add_blah_listener
211
+ # method on that component. So, if you need a ChangeListener you do:
212
+ #
213
+ # proc {|t,e| puts t }.to_listener(:change)
214
+ #
215
+ # The two parameters are a symbol for the method that Java called on this, and then the
216
+ # event argument.
142
217
  def to_listener(action)
143
218
  Profligacy::Swing::Listeners.const_get("#{action.to_s.capitalize}ListenerProc").new &self
144
219
  end
145
220
 
221
+ # Converts this Proc to a RunnableProc which implements the Runnable interface.
146
222
  def to_runnable
147
223
  Profligacy::Swing::RunnableProc.new &self
148
224
  end
149
225
  end
150
-
metadata CHANGED
@@ -53,11 +53,11 @@ requirements: []
53
53
  authors:
54
54
  - Zed A. Shaw
55
55
  platform: jruby
56
- date: 2007-07-09 04:00:00 +00:00
56
+ date: 2007-07-11 04:00:00 +00:00
57
57
  require_paths:
58
58
  - lib
59
59
  version: !ruby/object:Gem::Version
60
- version: 0.4.1
60
+ version: !str 1.0
61
61
  test_files: []
62
62
  bindir: bin
63
63
  dependencies: []