├── .gitattributes ├── COPYING ├── ChangeLog ├── README.md ├── Rakefile ├── data └── rjb │ └── jp │ └── co │ └── infoseek │ └── hp │ └── arton │ └── rjb │ └── RBridge.class ├── ext ├── MANIFEST ├── RBridge.java ├── depend.erb ├── extconf.rb ├── jniwrap.h ├── jp_co_infoseek_hp_arton_rjb_RBridge.h ├── load.c ├── riconv.c ├── riconv.h ├── rjb.c ├── rjb.h └── rjbexception.c ├── lib ├── rjb.rb ├── rjb │ ├── extension.rb │ ├── list.rb │ └── version.rb └── rjbextension.rb ├── pre-install.rb ├── readme.sj ├── readme.txt ├── rjb.gemspec ├── rjb.rake ├── samples ├── filechooser.rb └── unzip.rb ├── setup.rb └── test ├── Base.java ├── CallbackTest.java ├── ExtBase.java ├── IBase.java ├── JTest.java ├── JarTest.java ├── JarTest2.java ├── Test.java ├── Test105.java ├── Two.java ├── TwoCaller.java ├── anon-test-60.rb ├── exttest.rb ├── gctest.rb ├── jartest.jar ├── jartest.rb ├── jartest2.jar ├── jartest2.rb ├── jartest3.rb ├── jp └── co │ └── infoseek │ └── hp │ └── arton │ └── rjb │ ├── CallbackTest$Callback.class │ ├── CallbackTest.class │ ├── IBase.class │ ├── JarTest.class │ ├── JarTest2.class │ ├── Test$TestTypes.class │ ├── Test.class │ ├── Two.class │ └── TwoCaller.class ├── listtest.rb ├── osx_jvmcheck.rb ├── readme.txt ├── rjbtest.jar ├── test.rb ├── test105.rb ├── test_osxjvm.rb ├── test_osxload.rb └── test_unload.rb /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | # All systems will change to LF on commit if the file isn't present 3 | # in the index with CRLF already. 4 | * text=auto 5 | 6 | # Explicitly declare text files you want to always be normalized and converted 7 | # to native line endings on checkout. 8 | *.rb text 9 | *.h text 10 | *.c text 11 | *.java text 12 | *.md text 13 | *.txt text 14 | *.sj text 15 | *.rake text 16 | /ChangeLog text 17 | /Rakefile text 18 | /ext/MANIFEST text 19 | /ext/depend text 20 | 21 | # Denote all files that are truly binary and should not be modified. 22 | *.class binary 23 | *.jar binary 24 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | 504 | 505 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Wed May 1 2024 arton (reported and designed by uvlad7) 2 | * test/Test105.java 3 | add for test #105 (uvald7) 4 | * test/test105.rb 5 | add for test #105 (uvald7) 6 | * ext/rjb.c 7 | RJV_VERSION -> 1.7.3 8 | invoke_by_instance takes six parameters. six is called by method_missing or _invoke 9 | Wed May 1 2024 arton 10 | * test/jartest3.rb 11 | accept ClassNotFoundException for test 12 | * ext/load.c 13 | clear ruby error 14 | * ext/rjb.c 15 | change import => s_import for delegate. call Rjb::import instead of internal C fund. 16 | * lib/rjb.rb 17 | Rjb::import retry to import for NoSuchFieldException 18 | Fri Apr 26 2024 arton 19 | * ext/rjb.c 20 | RJB_VERSION -> 1.7.2 21 | * ext/extconf.rb 22 | change javah and javac console encoding according to the locale (reported by winezer0) 23 | * ext/load.c 24 | fix win32 and cygwin JVM path detection (reported by winezer0) 25 | * setup.rb 26 | remove duplicate line 27 | Sun Apr 14 2024 arton 28 | * ext/rjb.c 29 | RJB_VERSION -> 1.7.1 30 | * lib/rjb/extension.rb 31 | skip $LOAD_PATH check if absolute path was given 32 | * test/exttest.rb 33 | add absolute path test 34 | Sun Apr 14 2024 arton 35 | * ext/rjb.c 36 | RJB_VERSION -> 1.7.0 37 | java2jniname replaces second '.' to '$' for nested/inner classes 38 | * test/test.rb 39 | add test_load_nested/inner_class_as_java_naming_convention 40 | Thu Nov 9 2023 arton 41 | * ext/rjb.c 42 | RJB_VERSION -> 1.6.9 43 | * ext/riconv.c 44 | fix CESU-8 check 45 | * test/test.rb 46 | add test_jav_hangul_syllable for checking CESU-8 bug (char start with 0xed) 47 | Thu Sep 28 2023 chaddow 48 | #93 fake allocation framework to remove T_DATA warning 49 | * ext/rjb.c 50 | call rb_undef_alloc_fund if HAV_RB_DEFINE_ALLOC_FUNC 51 | Wed Mar 1 2023 mahendrapk 52 | Fix typo and broken URI 53 | * README.md 54 | * readme.txt 55 | Wed Feb 15 2023 geekontheway 56 | Fix aarch64 checking exception 57 | * ext/load.c 58 | put defined directive on one line 59 | * ext/rjb.c 60 | RJB_VERSION -> 1.6.7 (for Gem) 61 | Mon Dec 26 2022 chaadow 62 | ruby 3.2 support 63 | * ext/extconf.rb 64 | call File.exist? instead of deprecated File.exists? 65 | * ext/rjb.c 66 | RJB_VERSION -> 1.6.6 (for Gem) 67 | Fri Apr 8 2022 arton 68 | fix #85 69 | * data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class 70 | Gem rebuild by original binary (build by javac 1.4.2) 71 | * ext/rjb.c 72 | RJB_VERSION -> 1.6.5 (not changed any other codes but for Gem) 73 | Sun Feb 7 2021 arton 74 | * ext/extconf.rb 75 | use javah if `javac -version` didn't return the version number (ex. 1.4.2) 76 | * ext/rjb.c 77 | RJB_VERSION -> 1.6.4 78 | Sun Feb 7 2021 arton 79 | * ext/extconf.rb 80 | check javac and javah version 81 | * ext/rjb.c 82 | RJB_VERSION -> 1.6.3 83 | Sat Aug 1 2020 arton 84 | * ext/rjb.c 85 | RJB_VERSION -> 1.6.2 86 | * ext/load.c 87 | support OpenJDK directory structure (without jre) 88 | * lib/rjb.rb 89 | change copyright notice 90 | Wed Jul 17 2019 arton 91 | * ext/rjb.c 92 | RJB_VERSION -> 1.6.1 93 | * lib/rjb.rb 94 | java_methods and methods return symbol 95 | implements respond_to? for Java methods 96 | * ext/rbjexception.c 97 | delegate to JavaProxy for respond_to? (except for to_str and exception) 98 | * test/test.rb 99 | change java_methods test to adjust above change 100 | add respond_to? test 101 | Thu Jul 11 2019 arton 102 | * ext/rjb.c 103 | RJB_VERSION -> 1.6.0 104 | * ext/riconv.c 105 | encode/decode between utf-8 and cesu-8 if char was greater than \uffff 106 | Sun Feb 17 2019 lamby / arton 107 | * ext/rjb.c 108 | RJB_VERSION -> 1.5.9 109 | * ext/depend.erb 110 | it set javah line by ERB 111 | * ext/extconf.rb 112 | change javah to javac -h if it does not exist 113 | * ext/depend 114 | replaced by depend.erb 115 | Thu Jan 17 2019 arton 116 | * ext/rjbexception.c 117 | restore method_missing for the exception class 118 | * ext/rjb.c 119 | RJB_VERSION -> 1.5.8 120 | * test/test.rb 121 | add #60 test 122 | Fri Dec 28 2018 arton 123 | * ext/rjbexception.c 124 | fix #60; stable java derived exception class for raise 125 | * ext/rjb.c 126 | RJB_VERSION -> 1.5.7 127 | Thu Dec 27 2018 sean-npu 128 | * ext/load.c 129 | support aarch64 130 | * ext/rjb.c 131 | RJB_VERSION -> 1.5.6 132 | Sun Oct 30 arbox, maxberger and arton 133 | *Rakefile 134 | *rjb.gemspec 135 | Introduced GemSpec, Rakefile by arbox 136 | *lib/rjb/version.rb 137 | move version detection method from rjb.rake to lib/rjb by arbox 138 | *rjb.rake 139 | specify LoadError for catching failed require 140 | *ext/rjb.c 141 | RJB_VERSION -> 1.5.5 142 | *ext/load.c 143 | support Linux/ARM by maxberger 144 | Thu Oct 20 arton 145 | *test/test.rb 146 | change noarg static method calling test for JDK1.5 env. 147 | *test/Two.java, TwoCaller.java 148 | add package name 149 | *test/jp/co/infoseek/hp/arton/rjb/*.class 150 | recompile by JDK1.5 151 | Tue Jun 21 arton 152 | *lib/rjb.rb 153 | add JAVA_HOME/jre/bin to PATH env.vars for LoadLibrary can load further dlls 154 | Fri Nov 27 arton 155 | *ext/rjb.c 156 | RJB_VERSION -> 1.5.4 157 | copy back char[] contents into original array 158 | *test/test.rb 159 | add char array test (test_bothdirection_chararray) 160 | Sat Dec 20 2014 arton 161 | *ext/rjb.c 162 | RJB_VERSION -> 1.5.3 163 | select preferable constructor if argument is an array (for java.lang.String) 164 | *test/test.rb 165 | change literals to constants for kanji strings 166 | Sun Dec 14 2014 arton 167 | *lib/rjb.rb 168 | FakeDL for Rubinius 169 | *ext/riconv.c 170 | Change variable name for avoiding conflicion (Runinius) 171 | *ext/rjb.c 172 | RJB_VERSION -> 1.5.2 173 | Support Rubinius (Rubinius's block is T_OBJECT instead of T_DATA -> affected to anonclass) 174 | *test/test.rb 175 | skip fixnum range test if Rubinius 176 | Tue Sep 23 2014 arton 177 | *ext/rjb.c 178 | RJB_VERSION -> 1.5.1 179 | more weight for array and true/false 180 | Sat Sep 20 2014 arton 181 | *ext/rjb.c 182 | RJB_VERSION -> 1.5.0 183 | fix ctor_sigs with non argment ctor (represented by '') 184 | select preferable constructor 185 | *ext/riconv.c 186 | restruct encoding function 187 | *test/test.rb 188 | add constructor selection test (Ljava.lang.String; vs [B) 189 | Wed Jan 15 2014 arton 190 | *rjb.rake 191 | add lib/rjb/*.rb into gem 192 | Fri Jan 4 2014 arton 193 | *test/Test.java 194 | *test/rjbtest.jar 195 | add inner exception test 196 | *test/test.java 197 | add inner exception test 198 | Fri Jan 3 2014 arton 199 | *ext/rjb.c 200 | RJB_VERSION -> 1.4.9 201 | *ext/rjbexception.c 202 | make J#cause to the instance method for resolving Ruby 2.1 confliction. 203 | Sun Jun 23 2013 arton 204 | *ext/rjb.c 205 | RJB_VERSION -> 1.4.8 206 | create typed array exactly (reported by reinvanmeeteren on https://github.com/arton/rjb/issues/23) 207 | *test/test.rb 208 | add typed array test 209 | *test/Test.java 210 | add typed array test 211 | Tue Jun 18 2013 arton 212 | *ext/load.c 213 | check fiddle has dlopen (after ruby 2.0). 214 | Tue Jun 18 2013 arton 215 | *ext/rjb.c 216 | RJB_VERSION -> 1.4.7 217 | *ext/load.c 218 | rqeuire fiddle first, then dl. the patch originally created by Victor Lellis. 219 | Fri May 17 2013 arton 220 | *test/test.rb 221 | add Byte test 222 | Sun Apr 48 2013 arton 223 | *ext/rjb.o 224 | remove binary 225 | *ext/rjb.obj 226 | remove binary 227 | Sat Jan 26 2013 arton 228 | *ext/rjb.c 229 | RJB_VERSION -> 1.4.6 for new gem 230 | *RBridge.class 231 | Java Major Version -> 46 232 | Sun Jan 13 2013 arton 233 | *test/test.rb 234 | add bignum argument test 235 | *ext/rjb.c 236 | accept bignum argument for 'J' 237 | this bug(or at least mis spec.) was pointed by janroesner. Thanks janroesner ! 238 | Tue Dec 17 arton 239 | *test/test.rb 240 | add test_norarg_invoke 241 | *ext/rjb.c 242 | _invoke accepts noarg method call (reported by xiao li, thanks) 243 | RJB_VERSION -> 1.4.4 for new gem 244 | Wed Nov 14 arton 245 | *ext/rjb.c 246 | RJB_VERSION -> 1.4.3 for new gem 247 | *ext/extconf.rb 248 | remove checking dl.h, rjb not need to include it. 249 | Sat Oct 6 arton 250 | *ext/rjb.c 251 | RJB_VERSION -> 1.4.2 252 | *test/osx_jvmcheck.rb 253 | display vendor and version of JRE for OSX load test 254 | *test/osx_loadtest.rb 255 | add Oracle JVM support test for OSX 256 | *lib/rjb.rb 257 | add Oracle JVM support for OSX 258 | Sun Aug 19 arton 259 | *ext/rjb.c 260 | export bound object's original ruby object as @wrapped 261 | RJB_VERSION -> 1.4.1 262 | *lib/rjb.rb 263 | define Rjb_JavaBridge class for support @wrapped delegation 264 | *test/test.rb 265 | add @wrapped object invoking test 266 | Sun Apr 22 arton 267 | *ext/rjb.c 268 | add Rjb_JavaProxy#initialize_proxy method for preparing proxy instance. 269 | RJB_VERSION -> 1.4.0 270 | *lib/rjb 271 | add rjb own directory 272 | *lib/rjbextension.rb 273 | move contents into rjb/extension.rb 274 | *lib/rjb/extension.rb 275 | extension library to handle package name easily. 276 | *lib/rjb/list.rb 277 | implements each method for Iterable and Iterator. 278 | Sun Apr 22 arton 279 | *ext/rjb.c 280 | use URLClassLoader#addJar for Rjb::add_jar method. 281 | It accepts unhierarchic load order. 282 | *test/jartest2.jar 283 | for test Rjb::add_jar. this jar contains a class that extends class in jartest.jar 284 | *test/jartest.rb 285 | testing Rjb::add_jar, first jartest2.jar then jartest.jar 286 | *test/jartest2.rb 287 | testing Rjb::add_jar for an array. 288 | *test/jartest3.rb 289 | testing Rjb::add_jar in NoClassDefError condition. 290 | Sat Jan 28 arton 291 | *ext/rjb.c 292 | RJB_VERSION -> 1.3.9 293 | *ext/jniwrap.h 294 | skip __int64 definition if already defined (for latest mingw/gcc). 295 | Sat Dec 03 arton 296 | *ext/rjb.c 297 | RJB_VERSION -> 1.3.8 298 | ignore attach_jvm after rjb was unloaded. (Bug #29451) 299 | *test/test_unload.rb 300 | add test for unload. if Rjb run after unloading then it causes crush. 301 | Wed Nov 09 arton 302 | *ext/rjb.c 303 | RJB_VERSION -> 1.3.7 304 | *test/test.rb (test_reraise_exception) 305 | skip test if RUBY_VERSION =~ /^1\.8/ 306 | Wed Nov 09 arton 307 | *ext/rjb.c 308 | RJB_VERSION -> 1.3.6 309 | *ext/rjbexception.c 310 | add to_str method into the exception class. 311 | ruby internally calls the method when reraising the exception. 312 | *test/test.rb (test_reraise_exception) 313 | add reraise test 314 | Mon Jul 18 arton 315 | *ext/rjb.c 316 | fix inhiritance test. 317 | add anonymous inner class feature (as JRuby) 318 | *test/test.rb 319 | add anonymous inner class test 320 | *test/Two.java 321 | for anonymous inner class test 322 | *test/TwoCaller.java 323 | for anonymous inner class test 324 | Sat Jul 16 arton 325 | *ext/laod.c 326 | load server JVM if _WIN64 327 | *ext/rjb.c 328 | RJB_VERSION -> 1.3.5 329 | *test/test.rb 330 | add primitive_conversion and generic test. 331 | *test/Test.java 332 | add method that takes generic map and returns it 333 | Mon Nov 22 arton 334 | *ext/rjb.c 335 | RJB_VERSION -> 1.3.4 336 | require 'iconv' only if RUBY_VERSION < 1.9.0 337 | implicitly accept ruby's String for [B (byte array) 338 | copy back byte[] contents into original String 339 | *test/test.rb 340 | add string buffer test (test_bothdirection_buffer) 341 | Wed Nov 17 arton 342 | *ext/rjb.c 343 | RJB_VERSION -> 1.3.3 344 | *ext/load.c 345 | Check JAVA_HOME before load JVM (OS X specific) 346 | change int -> size_t for 64bit OS 347 | *test/test_osxjvm.rb 348 | add new test for OS X specific JVM detection. 349 | Sat Oct 30 arton 350 | *ext/rjb.c 351 | RJB_VERSION -> 1.3.2 352 | *extconf.rb 353 | Change OSX's include path detecting 354 | Tue Oct 26 arton 355 | *ext/rjb.c 356 | RJB_VERSION -> 1.3.1 357 | *rjb.rake 358 | make universal-darwin gem for Mac bundled ruby. 359 | Sun Oct 24 arton 360 | *sample/filechooser.rb 361 | omit Thread use (cause JVM crush with 1.9 and StackOverflow with 1.8) 362 | Sat Oct 23 arton 363 | *ext/rjb.c 364 | RJV_VERSION -> 1.3.0 365 | add loaded? class method. 366 | add add_classpath method (add jars without invoking load method) 367 | *ext/load.c 368 | OSX default jvm name changes to "JavaVM" (bug#28667 reported by Jeff Adams, thanks Jeff !) 369 | *ext/extconf.rb 370 | OSX javahome set to /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK 371 | *lib/rjbextension.rb 372 | use Rjb::add_classpath method instead of Kernel's class vars. 373 | *test/test.rb, test/exttest.rb 374 | fix add_jar test, previous version load them from jp directory. 375 | Tue Sep 22 arton 376 | *ext/rjb.c 377 | RJV_VERSION -> 1.2.10 378 | add add_jars method. add_jar and add_jars can take an array of jars. 379 | *test/test.rb 380 | add calling add_jar with an array test. 381 | Tue Sep 21 arton 382 | *ext/rjb.h 383 | export ClassLoader methods 384 | *ext/load.c 385 | move ClassLoader interaction codes into rjb.c 386 | *ext/rjb.c 387 | RJV_VERSION -> 1.2.9 388 | add add_jar method. 389 | loading classes throgh URLClassLoader if the user add Jars 390 | *lib/rjb.rb 391 | change MODIFIER module into a constant. Because it implys Rjb::import. 392 | change Config -> RbConfig for 1.9 393 | *test/test.rb 394 | add Rjb::add_jar test 395 | *test/JarTest.java 396 | *test/jartest.jar 397 | add for Rjb::add_jar test 398 | Fri Sep 17 arton 399 | *test/test.rb 400 | sort arguments order for test_java_methods (the order is implement dependent) 401 | add fixnum conversion test for 64bit platform (test_64fixnum) 402 | *ext/rjb.c 403 | RJV_VERSION -> 1.2.8 404 | fix rv2jlong bug, the solution was suggested by Ary Borenszweig 405 | Sun Aug 29 arton 406 | *ext/rjb.c 407 | ignore no arguments method signature. 408 | name base classes under Rjb module. 409 | *lib/rjb.rb 410 | implements public_methods and methods 411 | *test/test.rb 412 | add non arguments method sig test 413 | add methods, public_methods, java_methods test 414 | Thu Jul 22 arton 415 | *ext/rjb.c 416 | RJB_VERSION -> 1.2.6 417 | export jv2rv for rjbexception.c 418 | *ext/rjb.h 419 | export jv2rv for rjbexception.c 420 | *ext/rjbexception.c 421 | create and keep java exception object for its properties. 422 | *test/test.rb 423 | add Exception#cause test 424 | Wed Jun 9 arton 425 | *ext/load.c 426 | accept JAVA_HOME having an extra slash at the end 427 | *ext/rjb.c 428 | RJB_VERSION -> 1.2.5 429 | Fri Jun 5 arton 430 | *ext/rjb.h 431 | defin HAVE_LONG_LONG if no HAVE_LONG_LONG but LP64 432 | *ext/rjb.c 433 | remove unused variables 434 | RJB_VERSION -> 1.2.4 435 | Fri Jun 4 arton 436 | *ext/riconv.c 437 | remove unused function if build with Ruby 1.9 438 | *ext/rjb.c 439 | RJB_VERSION -> 1.2.3 440 | to accomodate with rubinius 441 | *ext/load.c 442 | to accomodate with rubinius 443 | *ext/rjbexception.c 444 | to accomodate with rubinius 445 | Sun May 30 arton 446 | *lib/rjbextension.rb 447 | Rjb extension from Andreas Ronge's neo4j 448 | - directly import jar by require method 449 | - Rjb::import without quotations (Java class as Ruby object) 450 | *test/exttest.rb 451 | test for rjbextension.rb 452 | *test/rjbtest.jar 453 | test file for rjbextension.rb 454 | Sat May 29 arton on behalf of atoulme 455 | *ext/rjb.c 456 | *ext/load.c 457 | *ext/rjbexception.c 458 | to accomodate with rubinius 459 | thanks atoulme ! 460 | Wed May 12 arton 461 | *test/test.rb 462 | add Class name for TestMixin module because ruby 1.9 doesn't handle the constant. 463 | Tue May 11 arton 464 | *ext/rjb.c 465 | fix duplicate method registering while no alias. 466 | add class methods for inspecting method signatures. 467 | add class_eval method for extending Java class 468 | *test/test.rb 469 | add class methods test for inspecting method signatures. 470 | add mixin tests 471 | Tue May 4 arton 472 | *ext/load.c 473 | corrected wrong function signature (BUG#28088), pointed and fixed by Romulo A. Ceccon (thanks) 474 | *ext/rjb.c 475 | using inheritance check while inspecting a object is RJB's instance (for extending it). 476 | Tue Mar 16 arton 477 | *ext/riconv.c 478 | change locale setting "" to "C", fixed by Fabien Sartor (rjb-Bugs-27968) 479 | *ext/rjb.c 480 | RJB_VERSION -> 1.2.1 481 | Sun Nov 1 arton 482 | *ext/load.c 483 | load jvm pointed by JVM_LIB environment variable first (suggested by Ittay Dror). 484 | *ext/rjb.c 485 | RJB_VERSION -> 1.2.0 486 | Sun Oct 11 arton 487 | *ext/extconf.rb 488 | add double quotation around include path for mingw compiler, original patched by Roger Pack (thanks) 489 | remove double quotaion around java_home variable for existing checking by File.directoy? 490 | *rjb.rake 491 | adding mingw support for the older version compatibility checking 492 | Thu Sep 10 arton 493 | *ext/load.c 494 | Correct previous code (always reload jvm if OSX < Snow Leopard) 495 | Clear DL's exception if success 496 | *ext/rjb.c 497 | RJB_VERSION -> 1.1.9 498 | *ext/rjbexception.c 499 | fit arguments for rb_raise to shut warning down 500 | Mon Sep 07 arton 501 | *ext/load.c 502 | Check no compat type dylib after loading was failed (for Snow Leopard) 503 | *ext/rjb.c 504 | RJB_VERSION -> 1.1.8 505 | Sun Feb 15 arton 506 | *test/test/rb 507 | add $KCODE and magic comment for iconv 508 | *ext/rjb.c 509 | RJB_VERSION -> 1.1.7 510 | Thu Feb 5 kuwa1 511 | *test/Test.java 512 | *test/test.rb 513 | add tests(Umlaut) 514 | *ext/rjb.c 515 | *ext/load.c 516 | fix for ruby19 517 | Sun Nov 16 arton 518 | *ext/load.c 519 | apply hpux patch, contributed by Ittay Dror. thanks 520 | Tue Aug 26 arton 521 | *ext/load.c, rjb.c, rjb.h 522 | export safe_funcall under the prefix 'rjb'. 523 | calling DL with rb_protect for avoiding exception. 524 | Mon Aug 25 arton 525 | *ext/load.c 526 | Fix checking the result for loading alternate_jvm_type. 527 | (patch from Kumar, thanks) 528 | Thu Aug 14 arton 529 | *ext/rjb.c, load.c, etc 530 | change comment line // -> /* */ because AIX's compiler 531 | add _AIX for load.c (this patch from Ittay Dror, thanks) 532 | *ext/load.c 533 | add ALT_JVM_TYPE for alternative jvm directory (by Kumar) 534 | Sun Jul 13 arton 535 | *ext/rjb.c 536 | display warning when Rjb load jvm implicitly if $DEBUG or $VERBOSE. 537 | Mon May 26 arton 538 | *ext/rjb.c 539 | correct char primitive conversion for Bigendian machine. 540 | use macroes for loading classes 541 | *ext/load.c 542 | adjust OS X's directory 543 | *ext/extconf.rb 544 | adjust OS X's directory if Home exists 545 | Thu Mar 27 arton 546 | *ext/rjb.c 547 | mark version 1.1.4 for the next release. 548 | *test/test.rb 549 | remove unload, because it fails. 550 | It's more important to assert each functions. 551 | Thu Mar 27 arton 552 | *ext/riconv.c 553 | activate conv tables for getenv configuration. 554 | Tue Mar 5 Kuwashima 555 | *ext/rjb.c 556 | *ext/rjb.h 557 | *ext/rjbexception.c 558 | add auto load method. 559 | Tue Mar 4 Kuwashima 560 | *ext/rjbexception.c 561 | *ext/rjb.c 562 | *test/test.rb 563 | clear(ignore) exception in current java thread, before some operation. 564 | *ext/rjbexception.c 565 | *ext/rjb.c 566 | add auto load for Rjb::bind, Rjb::throw 567 | *ext/rjb.c 568 | *test/test.rb 569 | add Rjb::unbind 570 | *test/test.rb 571 | add loading rubygems 572 | Sat Feb 23 arton 573 | *test/test.rb 574 | let test_field metod use Test.class instead of Point.class 575 | *test/Test.java 576 | add a public field for testing 577 | Fri Feb 22 arton 578 | *ext/rjb.c 579 | mark version 1.1.3 for the next release. 580 | Fri Feb 22 arton 581 | *ext/rjb.c 582 | fix field reference (bug# 18238) 583 | Wed Jan 9 arton 584 | *ext/rjb.h 585 | add some ruby macros that defined after 1.8.6 for compatibility 586 | Change RBridge.class by 1.4.2 587 | *data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class 588 | compiled by 1.4.2 version of Java 589 | *rjb.c 590 | mark version 1.1.2 for the next release. 591 | Tue Dec 27 Kuwashima 592 | *test/Test.java 593 | *test/test.rb 594 | *ext/depend 595 | *ext/load.c 596 | *ext/extconf.rb 597 | *ext/rjbexception.c 598 | *ext/rjb.c 599 | *ext/riconv.c 600 | change for compatibility with Ruby-1.9.0 601 | Tue Nov 20 arton 602 | *rjb.c 603 | mark version 1.10.12 for next relase. 604 | *load.c 605 | omit useless double-quotations from JAVA_HOME, maybe specifies a longpathname (but useless). 606 | Wed Nov 14 Kuwashima 607 | *rjb.c 608 | add error check to constructor. 609 | Fri Nov 9 arton 610 | *test.rb 611 | *Test.java 612 | add test for reproducing rjb-bugs-15430 613 | *rjb.c 614 | fix rjb-bugs-15430 that caused by bad array conversion. 615 | (generics method result signature is an object, but the real result is typed array) 616 | *riconv.c 617 | correct to get the number of array element. 618 | Tue Oct 23 Kuwashima 619 | *riconv.c 620 | Change string encoding conversion rule. 621 | Mon Oct 22 Kuwashima 622 | *riconv.c 623 | *riconv.h 624 | recycle iconv instance. 625 | *test/test.rb 626 | add cases for test_kjconv 627 | Sun Sep 23 arton 628 | *rjb.c 629 | version 1.0.9 630 | convert to Ruby's type if Rjb::primitive_converion is enalbed and the result type is java.lang.Object 631 | support the object conversion for a bignum to long. 632 | Sat Sep 15 arton 633 | *rjb.c 634 | version 1.0.8 635 | correction of 1.0.7, support long type. 636 | Fri Sep 14 arton 637 | *rjb.c 638 | version 1.0.7 639 | add auto primitive conversion toggled by Rjb::primitive_conversion 640 | *test.rb 641 | add test_auto_conv 642 | Sun Jun 17 arton 643 | *rjb.c 644 | add method aliases. 645 | setXxYy -> xx_yy= 646 | getXxYy -> xx_yy 647 | isXxYy -> xx_yy? 648 | xxYyZz -> xx_yy_zz 649 | *test.rb 650 | add a test for the method alias feature. 651 | Tue Nov 21 arton 652 | *rjb.c 653 | Skip the constant registering process, if the constant was already defined. 654 | *load.c 655 | *rjb.c 656 | *rjbexception.c 657 | *rjb.h 658 | add prefix 'rjb' for externed symbol names to avoid confliction. 659 | Sun Oct 08 arton (on behalf of richard apodaca) 660 | *load.c 661 | support AMD64 662 | Mon Sep 11 arton 663 | *test.rb 664 | add a test of arguments types are various array. 665 | *Test.java 666 | add a test of arguments types are various array. 667 | *rjb.c 668 | accept nil for array parameter. 669 | Sun Sep 10 arton 670 | *test.rb 671 | add a test of return type is an object wrapped an array 672 | *Test.java 673 | add a method that returns an object wrapped an array 674 | *rjb.c 675 | check array-mark in jv2rv for returned object was an array 676 | Tue Aug 1 arton 677 | *load.c 678 | *rjb.c 679 | change load pathname of the bridge class. 680 | *post-install.rb 681 | add for remove previous installed rjb.so. 682 | *rjb.rake 683 | add for build Gem. 684 | *rjb.rb 685 | for preparing the pathname constant of the bridge class. 686 | *depend 687 | chage binary name from rjb.so to rjbcore.so 688 | *extconf.rb 689 | chage binary name from rjb.so to rjbcore.so 690 | Mon Jul 31 arton 691 | *load.c 692 | fix buffer allocation 693 | 694 | Sun Jul 16 (Jun 22) Kuwashima and arton 695 | *rjb.c 696 | version 0.2.8 697 | *MANIFEST 698 | *depend 699 | *load.c 700 | *rjbexception.c 701 | change jni.h to jniwrap.h. 702 | change the bridge class's header according to JDK 5.0's javah. 703 | *jniwrap.h 704 | wrap jni.h for Cygin 705 | Sat Jun 10 14:10:05 2006 arton 706 | *rjb.c 707 | version 0.2.7 708 | support an array of arrays from ruby to java. 709 | 710 | Mon May 8 08:52:12 2006 arton 711 | *load.c 712 | revision 5 713 | support both Intel and PPC Mac. 714 | Patched version was contributed by Demetrius Nunes. 715 | 716 | Wed Apr 12 03:57:12 2006 arton 717 | *rjb.c 718 | version 0.2.6 719 | support an array of arrays. 720 | *test.rb 721 | add an array of arrays test, some tests are contributed by Darren Day. 722 | *Test.java 723 | add a test method that returns an array of arrays, some tests are 724 | contributed by Darren Day. 725 | 726 | Sat Dec 24 18:56:38 2005 arton 727 | *rjb.c 728 | version 0.2.5 729 | release String, Float, Array object after method call. 730 | *gctest.rb 731 | add for String object gc test 732 | 733 | Mon Sep 19 01:09:30 2005 arton 734 | *rjb.c 735 | version 0.2.4 736 | use null instead of empty string when String argument is nil 737 | omit unused local variable from jstring2val 738 | *test.rb 739 | add null string test (bug since utf-8 support) 740 | 741 | Tue Jun 28 01:57:07 2005 arton 742 | *rjb.c 743 | version 0.2.3 744 | convert result object to imported class if object is an instance of Class 745 | call Class#forName if argument count is 1 746 | *test.rb 747 | add test_importobj contributed by Mr. Kuwashima, thanks. 748 | 749 | Mon Jun 27 20:30:50 2005 arton 750 | treat Class.forName as Rjb::import 751 | *rjb.c 752 | version 0.2.2 753 | add method 'forName' into imported Class object 754 | if pass imported object to JVM, extract Class object from ruby object 755 | *test.rb 756 | add above tests 757 | 758 | Sat Jun 25 05:58:36 2005 arton 759 | most bugs were reported by Mr. Micael Weller, thanks. 760 | *rjb.c 761 | version 0.2.1 762 | correct derived static method search 763 | search class methods then class's instance methods when called by class 764 | avoid register non capitalized named constants into constants table 765 | correct capitalized named method search 766 | *riconv.c 767 | never call iconv if $KCODE is nil 768 | *load.c 769 | using path separator ; for cygwin (by Ryugate) 770 | 771 | Sun Apr 24 05:26:16 2005 arton 772 | *rb.c 773 | version 0.2.0 774 | delete localref if globalref was created. 775 | load can take the second argument for jvm 776 | *load.c 777 | load can take the second argument for jvm 778 | 779 | Mon Jan 17 02:40:21 2005 arton 780 | *rjb.c 781 | add 'throw' module function. 782 | move java exception handling functions into newly created rjbexception.c 783 | *rjb.h 784 | declations for rjb.c and rjbexception.c 785 | *rjbexception.c 786 | java exception handling functions, and 'throw' module function. 787 | *test.rb 788 | adding throw test. 789 | 790 | Wed Jan 12 00:01:08 2005 Kaspar Schiess and arton 791 | *rjb.c 792 | correct Rjb::load parameter evaluation (classpath). 793 | - many thanks to Mr.Schiess. 794 | 795 | Sun Nov 21 02:51:43 2004 Kuwashima and arton 796 | *rjb.c 797 | move dbcs-utf-8 auto conversion feature into riconv.? 798 | remove JNI version argument from Rjb::load. (bug reported by Mr.Tateishi) 799 | *load.c 800 | correct CLASSPATH setting (bad environment name).(bug reported by Mr.Tateishi) 801 | *riconv.c riconv.h (contributed by Mr.Kuwashima) 802 | DBCS - utf-8 auto conversion functions. 803 | *depend MANIFEST 804 | add riconv.? 805 | - many tanks to Mr.Kuwashima and Mr.Tateishi. 806 | 807 | Tue Oct 5 23:08:59 2004 Kuwashima and arton 808 | *test.rb 809 | add kanji conversion test 810 | *rjb.c 811 | add dbcs(sjis and euc-jp) - utf-8 auto conversion feature. 812 | the patch was contributed by Mr.Kuwashima, many thanks. 813 | 814 | Sun Oct 3 18:24:42 2004 arton 815 | *load.c 816 | JNIEnv* now using local variable instead of global one. 817 | Because AWT event use a worker thread, and JNI need thread's owned JNIEnv. 818 | *rjb.c 819 | JNIEnv* now using local variable instead of global one. 820 | Because AWT event use a worker thread, and JNI need thread's owned JNIEnv. 821 | This change was suggested by Mr.Kuwashima, he also tested the behavior, 822 | and gave me some test codes. 823 | and attach_current_thread is from Mr.Kuwashima's patch. 824 | Many thanks to Mr.Kuwashima. 825 | 826 | Sat Sep 25 03:25:45 2004 arton 827 | *rjb.c 828 | implements interface's method argument conversion. 829 | *test.rb 830 | add Comparable test (interface with method arguments) 831 | *Test.java 832 | add Comparable test method. 833 | 834 | Wed Sep 22 02:30:15 2004 arton 835 | *rjb.c 836 | correct constants load, using mid-class. 837 | convert null string to nil 838 | 839 | Wed Sep 22 00:05:32 2004 arton 840 | *rjb.c 841 | correct ruby type checking. If the parameter type is java.lang.String, rjb instance is always accepted. 842 | 843 | Mon Sep 20 22:02:53 2004 arton 844 | *rjb.c 845 | checking method/constructor signature with class when the argument is rjb's instance. 846 | Sun Sep 19 00:54:35 2004 arton 847 | *rjb.c 848 | convert Java exception to Ruby's StandardError derived class. 849 | checking method/constructor signature when invoking if no signatur argument is supplied. 850 | adding field accessor. 851 | 852 | Sun Sep 12 21:42:00 2004 arton 853 | *rjb.c 854 | call exception description when verbose = true. 855 | correct recursive import call (for Boolean). 856 | corrent method not found message creation. 857 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rjb is Ruby-Java bridge using Java Native Interface. 2 | 3 | The [Ruby Kaigi 2010](http://www.slideshare.net/artonx/j-ruby-kaigi-2010) 4 | Presentation on `Rjb`. 5 | 6 | A short [introduction](https://www.artonx.org/collabo/backyard/?RubyJavaBridge) 7 | in English. 8 | 9 | Some [examples](https://www.artonx.org/collabo/backyard/?RjbQandA) in 10 | Japanese, but the source code is clear for everybody. 11 | 12 | # How to install 13 | 14 | You need to install Java2 sdk, and setup `JAVA_HOME` enviromental 15 | varible except for OS X. I assume that OS X's `JAVA_HOME` is reported 16 | by calling `/usr/libexec/java_home`. 17 | 18 | This done please proceed with: 19 | 20 | ``` bash 21 | ruby setup.rb config 22 | ruby setup.rb setup 23 | ``` 24 | 25 | ``` bash 26 | # (in Unix) 27 | sudo ruby setup.rb install 28 | ``` 29 | 30 | or 31 | 32 | ``` bash 33 | # (in win32) 34 | ruby setup.rb install 35 | ``` 36 | 37 | # How to test 38 | 39 | On Windows based machines: 40 | 41 | ``` bash 42 | cd test 43 | ruby test.rb 44 | ``` 45 | 46 | On Unix based machines plese see `test/readme.unix`. You need to set 47 | `LD_LIBRARY_PATH` environmental variable to run `rjb`. 48 | 49 | # Notice for opening non-ASCII 7bit filename 50 | 51 | If you'll plan to open the non-ascii character named file by Java 52 | class through Rjb, it may require to set LC_ALL environment variable 53 | in your script. 54 | 55 | For example in Rails, set above line in `production.rb` as your environment: 56 | 57 | ``` bash 58 | ENV['LC_ALL'] = 'en_us.utf8' # or ja_JP.utf8 etc. 59 | ``` 60 | 61 | cf: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4733494 62 | (Thanks Paul for this information). 63 | 64 | # Contact 65 | artonx@yahoo.co.jp 66 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems/package_task' 2 | 3 | load './rjb.gemspec' 4 | 5 | Gem::PackageTask.new(RJB_GEMSPEC) do |pkg| 6 | pkg.gem_spec = RJB_GEMSPEC 7 | pkg.need_zip = false 8 | pkg.need_tar = false 9 | end 10 | 11 | desc 'Default Task' 12 | task :default => :package 13 | -------------------------------------------------------------------------------- /data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class -------------------------------------------------------------------------------- /ext/MANIFEST: -------------------------------------------------------------------------------- 1 | MANIFEST 2 | rjb.h 3 | riconv.h 4 | riconv.c 5 | rjb.c 6 | load.c 7 | rjbexception.c 8 | extconf.rb 9 | RBridge.java 10 | depend 11 | jniwrap.h 12 | -------------------------------------------------------------------------------- /ext/RBridge.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Rjb - Ruby <-> Java Bridge 3 | * Copyright(c) 2004 arton 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * $Id: RBridge.java 2 2006-04-11 19:04:40Z arton $ 16 | * $Log: RBridge.java,v $ 17 | * Revision 1.2 2004/06/19 09:05:00 arton 18 | * delete debug lines 19 | * 20 | * Revision 1.1 2004/06/19 09:00:19 arton 21 | * Initial revision 22 | * 23 | */ 24 | package jp.co.infoseek.hp.arton.rjb; 25 | import java.lang.reflect.InvocationHandler; 26 | import java.lang.reflect.Method; 27 | import java.lang.reflect.Proxy; 28 | 29 | public class RBridge implements InvocationHandler { 30 | public Object register(Class itf) { 31 | return Proxy.newProxyInstance(itf.getClassLoader(), 32 | new Class[] { itf }, this); 33 | } 34 | public Object invoke(Object proxy, Method method, Object[] args) 35 | throws Throwable { 36 | return call(method.getName(), proxy, args); 37 | } 38 | private native Object call(String methodName, Object target, Object[] args); 39 | } 40 | -------------------------------------------------------------------------------- /ext/depend.erb: -------------------------------------------------------------------------------- 1 | riconv.o : riconv.c jp_co_infoseek_hp_arton_rjb_RBridge.h 2 | rjb.o : rjb.c jp_co_infoseek_hp_arton_rjb_RBridge.h riconv.h rjb.h 3 | rjbexception.o : rjbexception.c jp_co_infoseek_hp_arton_rjb_RBridge.h riconv.h rjb.h 4 | load.o : load.c jp_co_infoseek_hp_arton_rjb_RBridge.h 5 | jp_co_infoseek_hp_arton_rjb_RBridge.h : jniwrap.h ../data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class 6 | <%= javah %> 7 | ../data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class : RBridge.java 8 | mkdir -p ../data/rjb/jp/co/infoseek/hp/arton/rjb 9 | javac -d ../data/rjb RBridge.java 10 | test : rjbcore.so ../test/jp/co/infoseek/hp/arton/rjb/Test.class ../test/jp/co/infoseek/hp/arton/rjb/IBase.class ../test/jp/co/infoseek/hp/arton/rjb/Base.class ../test/jp/co/infoseek/hp/arton/rjb/ExtBase.class 11 | ruby ../test/test.rb 12 | ../test/jp/co/infoseek/hp/arton/rjb/Test.class : ../test/Test.java 13 | javac ../test/Test.java 14 | $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/Test.class", "../test/jp/co/infoseek/hp/arton/rjb")' 15 | ../test/jp/co/infoseek/hp/arton/rjb/IBase.class : ../test/IBase.java 16 | javac ../test/IBase.java 17 | $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/IBase.class", "../test/jp/co/infoseek/hp/arton/rjb")' 18 | ../test/jp/co/infoseek/hp/arton/rjb/Base.class : ../test/Base.java ../test/jp/co/infoseek/hp/arton/rjb/IBase.class 19 | javac -classpath ../test ../test/Base.java 20 | $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/Base.class", "../test/jp/co/infoseek/hp/arton/rjb")' 21 | ../test/jp/co/infoseek/hp/arton/rjb/ExtBase.class : ../test/ExtBase.java 22 | javac -classpath ../test ../test/ExtBase.java 23 | $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/ExtBase.class", "../test/jp/co/infoseek/hp/arton/rjb")' 24 | -------------------------------------------------------------------------------- /ext/extconf.rb: -------------------------------------------------------------------------------- 1 | #---------------------------------- 2 | # extconf.rb 3 | # $Revision: $ 4 | # $Date: $ 5 | #---------------------------------- 6 | require 'mkmf' 7 | require 'erb' 8 | 9 | class Path 10 | 11 | def initialize() 12 | if File::ALT_SEPARATOR.nil? 13 | @file_separator = File::SEPARATOR 14 | else 15 | @file_separator = File::ALT_SEPARATOR 16 | end 17 | end 18 | 19 | def include(parent, child) 20 | inc = joint(parent, child) 21 | $INCFLAGS += " -I\"#{inc}\"" 22 | $CFLAGS += " -I\"#{inc}\"" 23 | inc 24 | end 25 | 26 | def joint(parent, child) 27 | parent + @file_separator + child 28 | end 29 | 30 | end 31 | 32 | javahome = ENV['JAVA_HOME'] 33 | if javahome.nil? && RUBY_PLATFORM =~ /darwin/ 34 | javahome = `/usr/libexec/java_home`.strip 35 | end 36 | unless javahome.nil? 37 | if javahome[0] == ?" && javahome[-1] == ?" 38 | javahome = javahome[1..-2] 39 | end 40 | raise "JAVA_HOME is not directory." unless File.directory?(javahome) 41 | pt = Path.new 42 | inc = pt.include(javahome, 'include') 43 | if !File.exist?(inc) && RUBY_PLATFORM =~ /darwin/ 44 | inc = pt.include('/System/Library/Frameworks/JavaVM.framework', 'Headers') 45 | end 46 | Dir.open(inc).each do |d| 47 | next if d[0] == ?. 48 | if File.directory?(pt.joint(inc, d)) 49 | pt.include(inc, d) 50 | break 51 | end 52 | end 53 | else 54 | raise "JAVA_HOME is not set." 55 | end 56 | 57 | 58 | def create_rjb_makefile 59 | if have_header("jni.h") 60 | have_func("locale_charset", "iconv.h") 61 | have_func("nl_langinfo", "langinfo.h") 62 | have_func("setlocale", "locale.h") 63 | have_func("getenv") 64 | $defs << "-DRJB_RUBY_VERSION_CODE="+RUBY_VERSION.gsub(/\./, '') 65 | create_header 66 | create_makefile("rjbcore") 67 | else 68 | raise "no jni.h in " + $INCFLAGS 69 | end 70 | end 71 | 72 | case RUBY_PLATFORM 73 | when /mswin32/ 74 | $CFLAGS += ' /W3' 75 | when /cygwin/, /mingw/ 76 | $defs << '-DNONAMELESSUNION' 77 | end 78 | 79 | JAVAH_COMMAND = 'javac -h . -classpath ../data/rjb RBridge.java'.freeze 80 | 81 | if find_executable('javah') 82 | if defined?(Encoding) && ''.respond_to?(:force_encoding) 83 | cversion = (`javac -version`.force_encoding(Encoding.locale_charmap).encode('utf-8') =~ /\d+\.\d+\.\d+/ ) ? $& : nil 84 | hversion = (`javah -version`.force_encoding(Encoding.locale_charmap).encode('utf-8') =~ /\d+\.\d+\.\d+/ ) ? $& : nil 85 | else 86 | cversion = (`javac -version` =~ /\d+\.\d+\.\d+/ ) ? $& : nil 87 | hversion = (`javah -version` =~ /\d+\.\d+\.\d+/ ) ? $& : nil 88 | end 89 | if cversion == hversion || cversion.nil? 90 | javah = 'javah -classpath ../data/rjb jp.co.infoseek.hp.arton.rjb.RBridge' 91 | else 92 | $stderr.puts "warning: javac and javah version unmatch => javah: #{hversion}, javac: #{cversion}" 93 | javah = JAVAH_COMMAND 94 | end 95 | else 96 | javah = JAVAH_COMMAND 97 | end 98 | File.open('depend', 'w') do |fout| 99 | fout.write ERB.new(IO::read('depend.erb')).result 100 | end 101 | create_rjb_makefile 102 | -------------------------------------------------------------------------------- /ext/jniwrap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Rjb - Ruby <-> Java Bridge 3 | * Copyright(c) 2006 Kuwashima 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * $Id: jniwrap.h 181 2012-01-28 05:28:41Z arton $ 16 | */ 17 | #ifndef _Included_jniwrap 18 | #define _Included_jniwrap 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #if defined(__GNUC__) && (defined(__CYGWIN32__) || defined(__MINGW32__)) 24 | #if !defined(__int64) 25 | typedef long long __int64; 26 | #endif 27 | #endif 28 | 29 | #include 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | #endif 35 | -------------------------------------------------------------------------------- /ext/jp_co_infoseek_hp_arton_rjb_RBridge.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class jp_co_infoseek_hp_arton_rjb_RBridge */ 4 | 5 | #ifndef _Included_jp_co_infoseek_hp_arton_rjb_RBridge 6 | #define _Included_jp_co_infoseek_hp_arton_rjb_RBridge 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: jp_co_infoseek_hp_arton_rjb_RBridge 12 | * Method: call 13 | * Signature: (Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; 14 | */ 15 | JNIEXPORT jobject JNICALL Java_jp_co_infoseek_hp_arton_rjb_RBridge_call 16 | (JNIEnv *, jobject, jstring, jobject, jobjectArray); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /ext/load.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Rjb - Ruby <-> Java Bridge 3 | * Copyright(c) 2004,2005,2006,2009,2010,2011,2020 arton 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * $Id: load.c 180 2011-12-05 16:34:29Z arton $ 16 | */ 17 | 18 | #include 19 | #include 20 | #include "ruby.h" 21 | #include "extconf.h" 22 | #if RJB_RUBY_VERSION_CODE < 190 23 | #include "intern.h" 24 | #include "st.h" 25 | #include "util.h" 26 | #else 27 | #include "ruby/intern.h" 28 | #include "ruby/st.h" 29 | #include "ruby/util.h" 30 | #endif 31 | #include "jniwrap.h" 32 | #include "jp_co_infoseek_hp_arton_rjb_RBridge.h" 33 | #include "rjb.h" 34 | 35 | #define JVM_TYPE "client" 36 | #define ALT_JVM_TYPE "classic" 37 | 38 | #if defined(_WIN32) || defined(__CYGWIN__) 39 | #if defined(__CYGWIN__) 40 | #define JVMDLL "%s/jre/bin/%s/jvm.dll" 41 | #define OPENJDK_JVMDLL "%s/bin/%s/jvm.dll" 42 | #define DIRSEPARATOR '/' 43 | #else 44 | #define JVMDLL "%s\\jre\\bin\\%s\\jvm.dll" 45 | #define OPENJDK_JVMDLL "%s\\bin\\%s\\jvm.dll" 46 | #define DIRSEPARATOR '\\' 47 | #if defined(_WIN64) 48 | #undef JVM_TYPE 49 | #define JVM_TYPE "server" 50 | #endif 51 | #endif 52 | #define CLASSPATH_SEP ';' 53 | #elif defined(__APPLE__) && defined(__MACH__) 54 | static char* JVMDLL = "%s/JavaVM"; 55 | #define DIRSEPARATOR '/' 56 | #define CLASSPATH_SEP ':' 57 | #define HOME_NAME "/Home" 58 | #define HOME_NAME_LEN strlen(HOME_NAME) 59 | #define DEFAULT_HOME "/System/Library/Frameworks/JavaVM.framework" 60 | #elif defined(_AIX) 61 | #define ARCH "ppc" 62 | #undef JVM_TYPE 63 | #define JVM_TYPE "j9vm" 64 | #elif defined(__hpux) 65 | #define JVMDLL "%s/jre/lib/%s/%s/libjvm.sl" 66 | #define OPENJDK_JVMDLL "%s/lib/%s/libjvm.sl" 67 | #define ARCH "PA_RISC" 68 | #undef JVM_TYPE 69 | #define JVM_TYPE "server" 70 | #define DIRSEPARATOR '/' 71 | #define CLASSPATH_SEP ':' 72 | #else /* defined(_WIN32) || defined(__CYGWIN__) */ 73 | #if defined(__sparc_v9__) 74 | #define ARCH "sparcv9" 75 | #elif defined(__sparc__) 76 | #define ARCH "sparc" 77 | #elif defined(__amd64__) 78 | #define ARCH "amd64" 79 | #undef JVM_TYPE 80 | #define JVM_TYPE "server" 81 | #elif defined(i586) || defined(__i386__) 82 | #define ARCH "i386" 83 | #elif defined(__arm__) 84 | #define ARCH "arm" 85 | #elif defined(__ARM64_ARCH_8__) || defined(__aarch64__) || defined(__ARMv8__) || defined(__ARMv8_A__) 86 | #define ARCH "aarch64" 87 | #undef JVM_TYPE 88 | #define JVM_TYPE "server" 89 | #endif 90 | #ifndef ARCH 91 | #include 92 | #endif 93 | #define JVMDLL "%s/jre/lib/%s/%s/libjvm.so" 94 | #define OPENJDK_JVMDLL "%s/lib/%s/libjvm.so" 95 | #define DIRSEPARATOR '/' 96 | #define CLASSPATH_SEP ':' 97 | #endif 98 | #if defined(__APPLE__) && defined(__MACH__) 99 | static char* CREATEJVM = "JNI_CreateJavaVM"; 100 | static char* GETDEFAULTJVMINITARGS = "JNI_GetDefaultJavaVMInitArgs"; 101 | #else 102 | #define CREATEJVM "JNI_CreateJavaVM" 103 | #define GETDEFAULTJVMINITARGS "JNI_GetDefaultJavaVMInitArgs" 104 | #endif 105 | 106 | typedef int (JNICALL *GETDEFAULTJAVAVMINITARGS)(void*); 107 | typedef int (JNICALL *CREATEJAVAVM)(JavaVM**, JNIEnv**, void*); 108 | 109 | static VALUE jvmdll = Qnil; 110 | static VALUE getdefaultjavavminitargsfunc; 111 | static VALUE createjavavmfunc; 112 | 113 | static const char* DLLibs[] = { "fiddle", "dl" }; 114 | static const char* DLNames[] = { "Fiddle", "DL" }; 115 | 116 | static VALUE safe_require(VALUE args) 117 | { 118 | return rb_require(StringValueCStr(args)); 119 | } 120 | 121 | static int open_jvm(char* libpath) 122 | { 123 | int sstat; 124 | VALUE* argv; 125 | size_t i; 126 | int state; 127 | 128 | if (rb_funcall(rb_cFile, rb_intern("exist?"), 1, rb_str_new2(libpath)) == RUBY_Qfalse) 129 | { 130 | if (RTEST(ruby_verbose)) 131 | { 132 | fprintf(stderr, "Rjb::load try to find but not exist %s\n", libpath); 133 | } 134 | return 0; 135 | } 136 | #if defined(RUBINIUS) 137 | i = 1; 138 | #else 139 | i = 0; 140 | #endif 141 | for (; i < COUNTOF(DLLibs); i++) 142 | { 143 | state = 0; 144 | rb_protect(safe_require, rb_str_new2(DLLibs[i]), &state); 145 | #if !defined(RUBINIUS) 146 | if (state || !rb_const_defined_at(rb_cObject, rb_intern(DLNames[i]))) 147 | { 148 | rb_set_errinfo(Qnil); 149 | if (i > 0) 150 | { 151 | rb_raise(rb_eRuntimeError, "Constants DL or Fiddle is not defined."); 152 | return 0; 153 | } 154 | } 155 | else 156 | #endif 157 | { 158 | sstat = 0; 159 | argv = ALLOCA_N(VALUE, 4); 160 | *argv = rb_const_get(rb_cObject, rb_intern(DLNames[i])); 161 | *(argv + 1) = rb_intern("dlopen"); 162 | *(argv + 2) = 1; 163 | *(argv + 3) = rb_str_new2(libpath); 164 | jvmdll = rb_protect(rjb_safe_funcall, (VALUE)argv, &sstat); 165 | if (!sstat) 166 | { 167 | break; 168 | } 169 | else 170 | { 171 | rb_set_errinfo(Qnil); 172 | if (i > 0) 173 | { 174 | return 0; 175 | } 176 | } 177 | } 178 | } 179 | /* get function pointers of JNI */ 180 | #if RJB_RUBY_VERSION_CODE < 190 181 | getdefaultjavavminitargsfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(GETDEFAULTJVMINITARGS), rb_str_new2("IP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0); 182 | createjavavmfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(CREATEJVM), rb_str_new2("IPPP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0); 183 | #else 184 | getdefaultjavavminitargsfunc = rb_funcall(jvmdll, rb_intern("[]"), 1, rb_str_new2(GETDEFAULTJVMINITARGS)); 185 | createjavavmfunc = rb_funcall(jvmdll, rb_intern("[]"), 1, rb_str_new2(CREATEJVM)); 186 | #endif 187 | return 1; 188 | } 189 | 190 | #if defined(__APPLE__) && defined(__MACH__) 191 | static int file_exist(const char* dir, const char* file) 192 | { 193 | VALUE path = rb_funcall(rb_cFile, rb_intern("join"), 2, 194 | rb_str_new2(dir), rb_str_new2(file)); 195 | VALUE ret = rb_funcall(rb_cFile, rb_intern("exist?"), 1, path); 196 | return RTEST(ret); 197 | } 198 | #endif 199 | 200 | /* 201 | * not completed, only valid under some circumstances. 202 | * load priority: OpenJDK -> SunJDK 203 | */ 204 | static int load_jvm(const char* jvmtype) 205 | { 206 | char* libpath; 207 | char* java_home; 208 | char* jh; 209 | 210 | jh = getenv("JAVA_HOME"); 211 | #if defined(__APPLE__) && defined(__MACH__) 212 | if (!jh) 213 | { 214 | jh = DEFAULT_HOME; 215 | } 216 | else 217 | { 218 | if (strlen(jh) > HOME_NAME_LEN) 219 | { 220 | size_t len = strlen(jh); 221 | char* p = ALLOCA_N(char, len + 8); 222 | jh = strcpy(p, jh); 223 | if (*(jh + len - 1) == '/') 224 | { 225 | --len; 226 | *(jh + len) = '\0'; 227 | } 228 | if (strcasecmp(jh + len - HOME_NAME_LEN, HOME_NAME) == 0) 229 | { 230 | strcpy(p + len, "/.."); 231 | } 232 | } 233 | if (!jvmtype && !file_exist(jh, "JavaVM")) 234 | { 235 | jh = DEFAULT_HOME; 236 | } 237 | } 238 | #endif 239 | if (!jh) 240 | { 241 | if (RTEST(ruby_verbose)) 242 | { 243 | fprintf(stderr, "no JAVA_HOME environment\n"); 244 | } 245 | return 0; 246 | } 247 | #if defined(_WIN32) 248 | if (*jh == '"' && *(jh + strlen(jh) - 1) == '"') 249 | { 250 | char* p = ALLOCA_N(char, strlen(jh) + 1); 251 | strcpy(p, jh + 1); 252 | *(p + strlen(p) - 1) = '\0'; 253 | jh = p; 254 | } 255 | #endif 256 | java_home = ALLOCA_N(char, strlen(jh) + 1); 257 | strcpy(java_home, jh); 258 | if (*(java_home + strlen(jh) - 1) == DIRSEPARATOR) 259 | { 260 | *(java_home + strlen(jh) - 1) = '\0'; 261 | } 262 | #if defined(__APPLE__) && defined(__MACH__) 263 | libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) + 1); 264 | sprintf(libpath, JVMDLL, java_home); 265 | return open_jvm(libpath); 266 | #else 267 | #if defined(_WIN32) || defined(__CYGWIN__) 268 | libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) 269 | + strlen(jvmtype) + 1); 270 | #else /* not Windows / MAC OS-X */ 271 | libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) 272 | + strlen(ARCH) + strlen(jvmtype) + 1); 273 | #endif 274 | sprintf(libpath, OPENJDK_JVMDLL, java_home, jvmtype); 275 | if (open_jvm(libpath)) 276 | { 277 | return 1; 278 | } 279 | #if defined(_WIN32) || defined(__CYGWIN__) 280 | sprintf(libpath, JVMDLL, java_home, jvmtype); 281 | #else /* not Windows / MAC OS-X */ 282 | sprintf(libpath, JVMDLL, java_home, ARCH, jvmtype); 283 | #endif 284 | return open_jvm(libpath); 285 | #endif /* __APPLE__ and __MACH */ 286 | } 287 | 288 | static int load_bridge(JNIEnv* jenv) 289 | { 290 | JNINativeMethod nmethod[1]; 291 | jbyte buff[8192]; 292 | char* bridge; 293 | size_t len; 294 | FILE* f; 295 | #if defined(RUBINIUS) 296 | VALUE v = rb_const_get(rb_cObject, rb_intern("RjbConf")); 297 | v = rb_const_get(v, rb_intern("BRIDGE_FILE")); 298 | #else 299 | VALUE v = rb_const_get_at(rb_const_get(rb_cObject, rb_intern("RjbConf")), 300 | rb_intern("BRIDGE_FILE")); 301 | #endif 302 | bridge = StringValuePtr(v); 303 | #if defined(DOSISH) 304 | bridge = ALLOCA_N(char, strlen(bridge) + 8); 305 | strcpy(bridge, StringValuePtr(v)); 306 | for (len = 0; bridge[len]; len++) 307 | { 308 | if (bridge[len] == '/') 309 | { 310 | bridge[len] = '\\'; 311 | } 312 | } 313 | #endif 314 | f = fopen(bridge, "rb"); 315 | if (f == NULL) 316 | { 317 | return -1; 318 | } 319 | len = fread(buff, 1, sizeof(buff), f); 320 | fclose(f); 321 | rjb_rbridge = (*jenv)->DefineClass(jenv, 322 | "jp/co/infoseek/hp/arton/rjb/RBridge", get_systemloader(jenv), buff, len); 323 | if (rjb_rbridge == NULL) 324 | { 325 | rjb_check_exception(jenv, 1); 326 | } 327 | rjb_register_bridge = (*jenv)->GetMethodID(jenv, rjb_rbridge, "register", 328 | "(Ljava/lang/Class;)Ljava/lang/Object;"); 329 | nmethod[0].name = "call"; 330 | nmethod[0].signature = "(Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"; 331 | nmethod[0].fnPtr = Java_jp_co_infoseek_hp_arton_rjb_RBridge_call; 332 | (*jenv)->RegisterNatives(jenv, rjb_rbridge, nmethod, 1); 333 | rjb_rbridge = (*jenv)->NewGlobalRef(jenv, rjb_rbridge); 334 | return 0; 335 | } 336 | 337 | void rjb_unload_vm() 338 | { 339 | if (RTEST(jvmdll)) 340 | { 341 | rb_funcall(jvmdll, rb_intern("close"), 0); 342 | jvmdll = Qnil; 343 | } 344 | } 345 | 346 | int rjb_create_jvm(JNIEnv** pjenv, JavaVMInitArgs* vm_args, char* userpath, VALUE argv) 347 | { 348 | static JavaVMOption soptions[] = { 349 | #if defined(__sparc_v9__) || defined(__sparc__) 350 | { "-Xusealtsigs", NULL }, 351 | #elif defined(linux) || defined(__linux__) 352 | { "-Xrs", NULL }, 353 | #elif defined(__APPLE__) && defined(_ARCH_PPC) 354 | { "-Xrs", NULL }, 355 | #endif 356 | #if defined(SHOW_JAVAGC) 357 | { "-verbose:gc", NULL }, 358 | #endif 359 | { "DUMMY", NULL }, /* for classpath count */ 360 | }; 361 | char* newpath; 362 | size_t len; 363 | int result; 364 | GETDEFAULTJAVAVMINITARGS initargs; 365 | CREATEJAVAVM createjavavm; 366 | JavaVMOption* options; 367 | size_t optlen; 368 | size_t i; 369 | VALUE optval; 370 | 371 | if (!RTEST(jvmdll)) 372 | { 373 | char* libjvm = getenv("JVM_LIB"); 374 | #if defined(_WIN32) 375 | if (libjvm && *libjvm == '"' && *(libjvm + strlen(libjvm) - 1) == '"') 376 | { 377 | char* p = ALLOCA_N(char, strlen(libjvm) + 1); 378 | strcpy(p, libjvm + 1); 379 | *(p + strlen(p) - 1) = '\0'; 380 | libjvm = p; 381 | } 382 | #endif 383 | if (libjvm == NULL || !open_jvm(libjvm)) 384 | { 385 | #if defined(__APPLE__) && defined(__MACH__) 386 | if (!(load_jvm(NULL))) 387 | { 388 | JVMDLL = "%s/Libraries/libjvm.dylib"; 389 | CREATEJVM = "JNI_CreateJavaVM_Impl"; 390 | GETDEFAULTJVMINITARGS = "JNI_GetDefaultJavaVMInitArgs_Impl"; 391 | #endif 392 | if (!(load_jvm(JVM_TYPE) || load_jvm(ALT_JVM_TYPE))) 393 | { 394 | return -1; 395 | } 396 | #if defined(__APPLE__) && defined(__MACH__) 397 | } 398 | #endif 399 | } 400 | 401 | #if RJB_RUBY_VERSION_CODE < 190 && !defined(RUBINIUS) 402 | ruby_errinfo = Qnil; 403 | #else 404 | rb_set_errinfo(Qnil); 405 | #endif 406 | } 407 | 408 | if (NIL_P(getdefaultjavavminitargsfunc)) 409 | { 410 | return -1; 411 | } 412 | initargs = (GETDEFAULTJAVAVMINITARGS)NUM2ULONG(getdefaultjavavminitargsfunc); 413 | result = initargs(vm_args); 414 | if (0 > result) 415 | { 416 | return result; 417 | } 418 | len = strlen(userpath); 419 | if (getenv("CLASSPATH")) 420 | { 421 | len += strlen(getenv("CLASSPATH")); 422 | } 423 | newpath = ALLOCA_N(char, len + 32); 424 | if (getenv("CLASSPATH")) 425 | { 426 | sprintf(newpath, "-Djava.class.path=%s%c%s", 427 | userpath, CLASSPATH_SEP, getenv("CLASSPATH")); 428 | } 429 | else 430 | { 431 | sprintf(newpath, "-Djava.class.path=%s", userpath); 432 | } 433 | optlen = 0; 434 | if (!NIL_P(argv)) 435 | { 436 | optlen += RARRAY_LEN(argv); 437 | } 438 | optlen += COUNTOF(soptions); 439 | options = ALLOCA_N(JavaVMOption, optlen); 440 | options->optionString = newpath; 441 | options->extraInfo = NULL; 442 | for (i = 1; i < COUNTOF(soptions); i++) 443 | { 444 | *(options + i) = soptions[i - 1]; 445 | } 446 | for (; i < optlen; i++) 447 | { 448 | optval = rb_ary_entry(argv, i - COUNTOF(soptions)); 449 | Check_Type(optval, T_STRING); 450 | (options + i)->optionString = StringValueCStr(optval); 451 | (options + i)->extraInfo = NULL; 452 | } 453 | vm_args->nOptions = (int)optlen; 454 | vm_args->options = options; 455 | vm_args->ignoreUnrecognized = JNI_TRUE; 456 | if (NIL_P(createjavavmfunc)) 457 | { 458 | return -1; 459 | } 460 | createjavavm = (CREATEJAVAVM)NUM2ULONG(createjavavmfunc); 461 | result = createjavavm(&rjb_jvm, pjenv, vm_args); 462 | if (!result) 463 | { 464 | result = load_bridge(*pjenv); 465 | if (RTEST(ruby_verbose) && result < 0) 466 | { 467 | fprintf(stderr, "failed to load the bridge class\n"); 468 | } 469 | } 470 | return result; 471 | } 472 | -------------------------------------------------------------------------------- /ext/riconv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Rjb - Ruby <-> Java Bridge 3 | * Copyright(c) 2004 Kuwashima 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * $Id: riconv.c 117 2010-06-04 12:16:25Z arton $ 16 | */ 17 | #include "ruby.h" 18 | #include "extconf.h" 19 | 20 | #if defined _WIN32 || defined __CYGWIN__ 21 | #include 22 | #endif 23 | 24 | #if defined HAVE_NL_LANGINFO 25 | #include 26 | static const char* const NL_EUC_TABLE[] = { "EUC-JISX0213", "EUC-JP", "EUC-JP-MS" }; 27 | static const char* const NL_SJIS_TABLE[] = { "SHIFT_JIS", "SHIFT_JISX0213", "WINDOWS-31J" }; 28 | #endif 29 | 30 | #if defined HAVE_SETLOCALE 31 | #include 32 | #endif 33 | static const char* const LOCALE_EUC_TABLE[] = { "japanese", "ja_JP.eucJP", "japanese.euc", "ja_JP", "ja_JP.ujis" }; 34 | static const char* const LOCALE_SJIS_TABLE[] = { "japanese.sjis", "ja_JP.SJIS" }; 35 | static const char* const LOCALE_UTF8_TABLE[] = { "ja_JP.UTF-8", "ja_JP.utf8" }; 36 | 37 | #include "riconv.h" 38 | 39 | static const char* const CS_EUCJP = "EUC-JP"; 40 | static const char* const CS_CP932 = "CP932"; 41 | static const char* const CS_SJIS = "SHIFT_JIS"; 42 | static const char* const CS_UTF8 = "UTF-8"; 43 | 44 | 45 | #if RJB_RUBY_VERSION_CODE < 190 46 | static VALUE objIconvJ2R; 47 | static VALUE objIconvR2J; 48 | static const char* charcode; //is this necessary? 49 | static char Kcode = '\0'; 50 | 51 | static int find_table(const char* const str, const char* const table[]) 52 | { 53 | int i; 54 | int size = sizeof(table) / sizeof(table[0]); 55 | for (i = 0; i < size; ++i) 56 | { 57 | if (strstr(str, table[i])) return 1; 58 | } 59 | return 0; 60 | } 61 | #endif 62 | 63 | #if RJB_RUBY_VERSION_CODE < 190 64 | static const char* get_charcode_name_by_locale(const char* const name) 65 | { 66 | if (find_table(name, LOCALE_UTF8_TABLE)) 67 | return NULL; 68 | else if (find_table(name, LOCALE_EUC_TABLE)) 69 | return CS_EUCJP; 70 | else if (find_table(name, LOCALE_SJIS_TABLE)) 71 | return CS_SJIS; 72 | else 73 | return NULL; 74 | } 75 | /* 76 | * Get better charcode name. 77 | */ 78 | static const char* get_charcode_name() 79 | { 80 | const char* result = NULL; 81 | const char* lang = NULL; 82 | 83 | switch(Kcode) 84 | { 85 | case 'E': 86 | result = CS_EUCJP; 87 | break; 88 | case 'S': 89 | #if defined _WIN32 || defined __CYGWIN__ 90 | result = CS_CP932; 91 | #else 92 | result = CS_SJIS; 93 | #endif 94 | break; 95 | case 'U': 96 | //as is. 97 | break; 98 | case 'N': 99 | default: 100 | #if defined _WIN32 || defined __CYGWIN__ 101 | if (932 == GetACP()) result = CS_CP932; 102 | #elif defined HAVE_NL_LANGINFO 103 | setlocale(LC_ALL, "C"); //initialize 104 | lang = nl_langinfo(CODESET); 105 | if (find_table(lang, NL_EUC_TABLE)) 106 | result = CS_EUCJP; 107 | else if (find_table(lang, NL_SJIS_TABLE)) 108 | result = CS_SJIS; 109 | #elif defined HAVE_SETLOCALE 110 | setlocale(LC_ALL, "C"); //initialize 111 | result = get_charcode_name_by_locale(setlocale(LC_ALL, NULL)); 112 | #elif defined HAVE_GETENV 113 | if (result = get_charcode_name_by_locale(getenv("LC_ALL"))) 114 | ; 115 | else if (result = get_charcode_name_by_locale(getenv("LC_CTYPE"))) 116 | ; 117 | else if (result = get_charcode_name_by_locale(getenv("LANG"))) 118 | ; 119 | #endif 120 | break; 121 | } 122 | return result; 123 | } 124 | #endif 125 | 126 | #if RJB_RUBY_VERSION_CODE < 190 127 | static void reinit() 128 | { 129 | charcode = get_charcode_name(); 130 | if (charcode) 131 | { 132 | VALUE rb_iconv_klass = rb_const_get(rb_cObject, rb_intern("Iconv")); 133 | if (RTEST(rb_iconv_klass)) { 134 | ID sym_new = rb_intern("new"); 135 | rb_gc_unregister_address(&objIconvR2J); 136 | objIconvR2J = rb_funcall(rb_iconv_klass, sym_new, 2, rb_str_new2(CS_UTF8), rb_str_new2(charcode)); 137 | rb_gc_register_address(&objIconvR2J); 138 | rb_gc_unregister_address(&objIconvJ2R); 139 | objIconvJ2R = rb_funcall(rb_iconv_klass, sym_new, 2, rb_str_new2(charcode), rb_str_new2(CS_UTF8)); 140 | rb_gc_register_address(&objIconvJ2R); 141 | } 142 | } 143 | else 144 | { 145 | objIconvR2J = objIconvJ2R = Qnil; 146 | } 147 | } 148 | #endif 149 | 150 | #if RJB_RUBY_VERSION_CODE < 190 151 | static void check_kcode() 152 | { 153 | VALUE rb_iconv_klass = rb_const_get(rb_cObject, rb_intern("Iconv")); 154 | VALUE kcode = rb_gv_get("$KCODE"); 155 | if (RTEST(rb_iconv_klass) && TYPE(kcode) == T_STRING) { 156 | char* kcodep = StringValuePtr(kcode); 157 | char upper_kcode = toupper(*kcodep); 158 | if (Kcode != upper_kcode) 159 | { 160 | Kcode = upper_kcode; 161 | reinit(); 162 | } 163 | } 164 | else 165 | { 166 | objIconvR2J = objIconvJ2R = Qnil; 167 | } 168 | } 169 | #else 170 | VALUE cEncoding = Qnil; 171 | VALUE encoding_utf8 = Qnil; 172 | static void init_encoding_vars() 173 | { 174 | cEncoding = rb_const_get(rb_cObject, rb_intern("Encoding")); 175 | encoding_utf8 = rb_const_get(cEncoding, rb_intern("UTF_8")); 176 | } 177 | static int contains_surrogate_pair(const unsigned char* p) 178 | { 179 | while (*p) 180 | { 181 | switch (*p & 0xf0) 182 | { 183 | case 0xf0: 184 | return 1; 185 | case 0xe0: 186 | p += 3; 187 | break; 188 | default: 189 | p += (*p & 0x80) ? 2 : 1; 190 | } 191 | } 192 | return 0; 193 | } 194 | static int contains_auxchar(const unsigned char* p) 195 | { 196 | while (*p) 197 | { 198 | if (*p == 0xed && *(p + 1) && *(p + 2)) 199 | { 200 | #if defined(DEBUG) 201 | printf("find %02x %02x %02x %02x %02x %02x\n", *p, *(p + 1), *(p + 2), *(p + 3), *(p + 4), *(p + 5)); 202 | #endif 203 | if ((*(p + 1) & 0xa0) == 0xa0 && (*(p + 2) & 0xb0) == 0xb0) 204 | { 205 | return 1; 206 | } 207 | } 208 | switch (*p & 0xe0) 209 | { 210 | case 0xe0: 211 | p++; 212 | case 0xc0: 213 | p++; 214 | default: 215 | p++; 216 | } 217 | } 218 | return 0; 219 | } 220 | 221 | static VALUE encode_to_cesu8(const unsigned char* p) 222 | { 223 | size_t len = strlen(p); 224 | char* newstr = ALLOCA_N(char, len + (len + 1) / 2); 225 | char* dest = newstr; 226 | int sval, i; 227 | while (*p) 228 | { 229 | switch (*p & 0xf0) 230 | { 231 | case 0xf0: 232 | sval = *p++ & 7; 233 | for (i = 0; i < 3; i++) 234 | { 235 | sval <<= 6; 236 | sval |= (*p++ & 0x3f); 237 | } 238 | *dest++ = '\xed'; 239 | *dest++ = 0xa0 | (((sval >> 16) - 1) & 0x0f); 240 | *dest++ = 0x80 | ((sval >> 10) & 0x3f); 241 | *dest++ = '\xed'; 242 | *dest++ = 0xb0 | ((sval >> 6) & 0x0f); 243 | *dest++ = 0x80 | (sval & 0x3f); 244 | break; 245 | case 0xe0: 246 | *dest++ = *p++; 247 | case 0xc0: 248 | case 0xc1: 249 | *dest++ = *p++; 250 | default: 251 | *dest++ = *p++; 252 | } 253 | } 254 | return rb_str_new(newstr, dest - newstr); 255 | } 256 | static VALUE encode_to_utf8(const unsigned char* p) 257 | { 258 | size_t len = strlen(p); 259 | char* newstr = ALLOCA_N(char, len); 260 | char* dest = newstr; 261 | int sval, i; 262 | while (*p) 263 | { 264 | if (*p == 0xed) 265 | { 266 | char v = *(p + 1); 267 | char w = *(p + 2); 268 | char y = *(p + 4); 269 | char z = *(p + 5); 270 | p += 6; 271 | sval = 0x10000 + ((v & 0x0f) << 16) + ((w & 0x3f) << 10) + ((y & 0x0f) << 6) + (z & 0x3f); 272 | sval = (((v + 1) & 0x0f) << 16) + ((w & 0x3f) << 10) + ((y & 0x0f) << 6) + (z & 0x3f); 273 | *dest++ = 0xf0 | ((sval >> 18)); 274 | *dest++ = 0x80 | ((sval >> 12) & 0x3f); 275 | *dest++ = 0x80 | ((sval >> 6) & 0x3f); 276 | *dest++ = 0x80 | (sval & 0x3f); 277 | continue; 278 | } 279 | switch (*p & 0xe0) 280 | { 281 | case 0xe0: 282 | *dest++ = *p++; 283 | case 0xc0: 284 | case 0xc1: 285 | *dest++ = *p++; 286 | default: 287 | *dest++ = *p++; 288 | } 289 | } 290 | return rb_str_new(newstr, dest - newstr); 291 | } 292 | #endif 293 | 294 | #if defined(DEBUG) 295 | static void debug_out(VALUE v) 296 | { 297 | char* p = StringValuePtr(v); 298 | printf("-- %d, %d, %s\n", rb_num2long(rb_funcall(v, rb_intern("size"), 0)), 299 | strlen(p), p); 300 | fflush(stdout); 301 | } 302 | #else 303 | #define debug_out(n) 304 | #endif 305 | 306 | VALUE exticonv_local_to_utf8(VALUE local_string) 307 | { 308 | #if RJB_RUBY_VERSION_CODE < 190 309 | check_kcode(); 310 | if(RTEST(objIconvR2J)) 311 | { 312 | return rb_funcall(objIconvR2J, rb_intern("iconv"), 1, local_string); 313 | } 314 | else 315 | { 316 | return local_string; 317 | } 318 | #else 319 | VALUE encoding; 320 | if (NIL_P(cEncoding)) 321 | { 322 | init_encoding_vars(); 323 | } 324 | encoding = rb_funcall(local_string, rb_intern("encoding"), 0); 325 | if (encoding != encoding_utf8) 326 | { 327 | VALUE ret = rb_funcall(local_string, rb_intern("encode"), 2, encoding_utf8, encoding); 328 | debug_out(local_string); 329 | debug_out(ret); 330 | local_string = ret; 331 | } 332 | if (contains_surrogate_pair(StringValuePtr(local_string))) 333 | { 334 | local_string = encode_to_cesu8(StringValuePtr(local_string)); 335 | } 336 | return local_string; 337 | #endif 338 | } 339 | 340 | VALUE exticonv_utf8_to_local(VALUE utf8_string) 341 | { 342 | #if RJB_RUBY_VERSION_CODE < 190 343 | check_kcode(); 344 | if(RTEST(objIconvR2J)) 345 | { 346 | return rb_funcall(objIconvJ2R, rb_intern("iconv"), 1, utf8_string); 347 | } 348 | else 349 | { 350 | return utf8_string; 351 | } 352 | #else 353 | if (NIL_P(cEncoding)) 354 | { 355 | init_encoding_vars(); 356 | } 357 | if (contains_auxchar(StringValuePtr(utf8_string))) 358 | { 359 | utf8_string = encode_to_utf8(StringValuePtr(utf8_string)); 360 | } 361 | return rb_funcall(utf8_string, rb_intern("force_encoding"), 1, encoding_utf8); 362 | #endif 363 | } 364 | -------------------------------------------------------------------------------- /ext/riconv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Rjb - Ruby <-> Java Bridge 3 | * Copyright(c) 2004 Kuwashima 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * $Id: riconv.h 43 2007-12-26 18:55:04Z kuwa1 $ 16 | */ 17 | #ifndef _RICONV_H 18 | #define _RICONV_H 19 | 20 | 21 | VALUE exticonv_local_to_utf8(VALUE); 22 | VALUE exticonv_utf8_to_local(VALUE); 23 | 24 | #endif /* _RICONV_H */ 25 | -------------------------------------------------------------------------------- /ext/rjb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Rjb - Ruby <-> Java Bridge 3 | * Copyright(c) 2004,2005 arton 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * $Id: rjb.h 180 2011-12-05 16:34:29Z arton $ 16 | * $Log: rjb.h,v $ 17 | * Revision 1.1 2005/01/16 17:36:10 arton 18 | * Initial revision 19 | * 20 | * 21 | */ 22 | 23 | #ifndef RJB_H 24 | #define RJB_H 25 | 26 | #if RJB_RUBY_VERSION_CODE < 190 27 | #if !defined(RHASH_TBL) 28 | #define RHASH_TBL(x) RHASH((x))->tbl 29 | #endif 30 | #endif 31 | 32 | #if !defined(RSTRING_LEN) 33 | #define RSTRING_LEN(s) (RSTRING(s)->len) 34 | #endif 35 | #if !defined(RSTRING_PTR) 36 | #define RSTRING_PTR(s) (RSTRING(s)->ptr) 37 | #endif 38 | #if !defined(RARRAY_LEN) 39 | #define RARRAY_LEN(s) (RARRAY(s)->len) 40 | #endif 41 | #if !defined(RARRAY_PTR) 42 | #define RARRAY_PTR(s) (RARRAY(s)->ptr) 43 | #endif 44 | 45 | #if !defined(COUNTOF) 46 | #define COUNTOF(x) (sizeof(x)/sizeof(x[0])) 47 | #endif 48 | 49 | #if !defined(_I64_MIN) 50 | #define _I64_MIN (-9223372036854775807i64 - 1) 51 | #endif 52 | #if !defined(_I64_MAX) 53 | #define _I64_MAX 9223372036854775807i64 54 | #endif 55 | 56 | #if !defined(HAVE_LONG_LONG) && defined(__LP64__) 57 | #define HAVE_LONG_LONG 1 58 | #endif 59 | 60 | /* in load.c */ 61 | extern int rjb_create_jvm(JNIEnv** pjenv, JavaVMInitArgs*, char*, VALUE); 62 | 63 | /* in rjb.c */ 64 | extern JavaVM* rjb_jvm; 65 | extern jclass rjb_rbridge; 66 | extern jmethodID rjb_register_bridge; 67 | extern VALUE rjb_loaded_classes; 68 | extern jmethodID rjb_class_getName; 69 | extern jclass rjb_j_throwable; 70 | extern jmethodID rjb_throwable_getMessage; 71 | extern JNIEnv* rjb_attach_current_thread(void); 72 | extern jclass rjb_find_class(JNIEnv* jenv, VALUE name); 73 | extern void rjb_release_string(JNIEnv *jenv, jstring str, const char* chrs); 74 | extern VALUE rjb_load_vm_default(); 75 | extern void rjb_unload_vm(); 76 | extern VALUE rjb_safe_funcall(VALUE args); 77 | extern VALUE jv2rv(JNIEnv* jenv, jvalue val); 78 | extern jobject get_systemloader(JNIEnv* jenv); 79 | extern jclass rjb_find_class_by_name(JNIEnv* jenv, const char* name); 80 | 81 | /* in rjbexception.c */ 82 | extern VALUE rjb_get_exception_class(JNIEnv* jenv, jstring str); 83 | extern void rjb_check_exception(JNIEnv* jenv, int t); 84 | extern VALUE rjb_s_throw(int, VALUE*, VALUE); 85 | 86 | /* conversion functions */ 87 | typedef void (*R2J)(JNIEnv*, VALUE, jvalue*, const char*, int); 88 | typedef VALUE (*J2R)(JNIEnv*, jvalue); 89 | typedef jarray (*R2JARRAY)(JNIEnv*, VALUE, const char*); 90 | typedef void (JNICALL *RELEASEARRAY)(JNIEnv*, jobject, void*, jint); 91 | typedef jlong (JNICALL *INVOKEAL)(JNIEnv*, jobject, jmethodID, const jvalue*); 92 | typedef jdouble (JNICALL *INVOKEAD)(JNIEnv*, jobject, jmethodID, const jvalue*); 93 | typedef jfloat (JNICALL *INVOKEAF)(JNIEnv*, jobject, jmethodID, const jvalue*); 94 | typedef jboolean (JNICALL *INVOKEAZ)(JNIEnv*, jobject, jmethodID, const jvalue*); 95 | typedef jshort (JNICALL *INVOKEAS)(JNIEnv*, jobject, jmethodID, const jvalue*); 96 | typedef jobject (JNICALL *INVOKEA)(JNIEnv*, jobject, jmethodID, const jvalue*); 97 | typedef VALUE (*CONV)(JNIEnv*, void*); 98 | 99 | /* 100 | * internal method class 101 | */ 102 | struct cls_constructor { 103 | jmethodID id; 104 | int arg_count; 105 | R2J* arg_convert; 106 | char* method_signature; 107 | char result_signature; 108 | char result_arraydepth; 109 | }; 110 | 111 | struct cls_method { 112 | struct cls_constructor basic; 113 | ID name; 114 | int static_method; 115 | off_t method; 116 | J2R result_convert; 117 | /* overload only */ 118 | struct cls_method* next; 119 | }; 120 | 121 | /* 122 | * internal field class 123 | */ 124 | struct cls_field { 125 | ID name; 126 | jfieldID id; 127 | char* field_signature; 128 | char result_signature; 129 | char result_arraydepth; 130 | R2J arg_convert; 131 | J2R value_convert; 132 | int readonly; 133 | int static_field; 134 | }; 135 | 136 | /* 137 | * Object instance 138 | */ 139 | struct jvi_data { 140 | jclass klass; /* class */ 141 | jobject obj; /* instance */ 142 | st_table* methods; 143 | st_table* fields; 144 | }; 145 | 146 | /* 147 | * Class instance 148 | */ 149 | struct jv_data { 150 | struct jvi_data idata; 151 | st_table* static_methods; 152 | struct cls_constructor** constructors; 153 | }; 154 | 155 | /* 156 | * Bridge instance 157 | */ 158 | struct rj_bridge { 159 | jobject bridge; 160 | jobject proxy; 161 | VALUE wrapped; 162 | }; 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /ext/rjbexception.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Rjb - Ruby <-> Java Bridge 3 | * Copyright(c) 2004,2005,2006,2010 arton 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * $Id: rjbexception.c 174 2011-11-09 13:47:43Z arton $ 16 | */ 17 | 18 | #include "ruby.h" 19 | #include "extconf.h" 20 | #if RJB_RUBY_VERSION_CODE < 190 21 | #include "st.h" 22 | #else 23 | #include "ruby/st.h" 24 | #endif 25 | #include "jniwrap.h" 26 | #include "riconv.h" 27 | #include "rjb.h" 28 | 29 | static VALUE missing_delegate(int argc, VALUE* argv, VALUE self) 30 | { 31 | ID rmid = rb_to_id(argv[0]); 32 | return rb_funcallv(rb_ivar_get(self, rb_intern("@cause")), rmid, argc - 1, argv + 1); 33 | } 34 | 35 | static VALUE get_cause(VALUE self) 36 | { 37 | return rb_funcall(rb_ivar_get(self, rb_intern("@cause")), rb_intern("cause"), 0); 38 | } 39 | 40 | static VALUE ex_respond_to(int argc, VALUE* argv, VALUE self) 41 | { 42 | if (argc < 1 || argc > 2) 43 | { 44 | rb_raise(rb_eArgError, "respond_to? require 1 or 2 arguments"); 45 | } 46 | if (rb_to_id(argv[0]) == rb_intern("to_str")) 47 | { 48 | return Qfalse; 49 | } 50 | else if (rb_to_id(argv[0]) == rb_intern("exception")) 51 | { 52 | return Qtrue; 53 | } 54 | else 55 | { 56 | return rb_funcallv(rb_ivar_get(self, rb_intern("@cause")), rb_intern("respond_to?"), argc, argv); 57 | } 58 | } 59 | 60 | /* 61 | * handle Java exception 62 | * At this time, the Java exception is defined without the package name. 63 | * This design may change in future release. 64 | */ 65 | VALUE rjb_get_exception_class(JNIEnv* jenv, jstring str) 66 | { 67 | VALUE rexp; 68 | char* pcls; 69 | VALUE cname; 70 | const char* p = (*jenv)->GetStringUTFChars(jenv, str, JNI_FALSE); 71 | char* clsname = ALLOCA_N(char, strlen(p) + 1); 72 | strcpy(clsname, p); 73 | rjb_release_string(jenv, str, p); 74 | pcls = strrchr(clsname, '.'); 75 | if (pcls) 76 | { 77 | pcls++; 78 | } 79 | else 80 | { 81 | pcls = clsname; 82 | } 83 | cname = rb_str_new2(pcls); 84 | rexp = rb_hash_aref(rjb_loaded_classes, cname); 85 | if (rexp == Qnil) 86 | { 87 | rexp = rb_define_class(pcls, rb_eStandardError); 88 | rb_define_method(rexp, "cause", get_cause, 0); 89 | rb_define_method(rexp, "method_missing", missing_delegate, -1); 90 | rb_define_method(rexp, "respond_to?", ex_respond_to, -1); 91 | #if defined(HAVE_RB_HASH_ASET) || defined(RUBINIUS) 92 | rb_hash_aset(rjb_loaded_classes, cname, rexp); 93 | #else 94 | #ifdef RHASH_TBL 95 | st_insert(RHASH_TBL(rjb_loaded_classes), cname, rexp); 96 | #else 97 | st_insert(RHASH(rjb_loaded_classes)->tbl, cname, rexp); 98 | #endif 99 | #endif 100 | 101 | } 102 | return rexp; 103 | } 104 | 105 | /* 106 | * throw newly created exception with supplied message. 107 | */ 108 | VALUE rjb_s_throw(int argc, VALUE* argv, VALUE self) 109 | { 110 | VALUE klass; 111 | VALUE message; 112 | JNIEnv* jenv = NULL; 113 | 114 | rjb_load_vm_default(); 115 | 116 | jenv = rjb_attach_current_thread(); 117 | (*jenv)->ExceptionClear(jenv); 118 | 119 | if (rb_scan_args(argc, argv, "11", &klass, &message) == 2) 120 | { 121 | jclass excep = rjb_find_class(jenv, klass); 122 | if (excep == NULL) 123 | { 124 | rb_raise(rb_eRuntimeError, "`%s' not found", StringValueCStr(klass)); 125 | } 126 | (*jenv)->ThrowNew(jenv, excep, StringValueCStr(message)); 127 | } 128 | else 129 | { 130 | struct jvi_data* ptr; 131 | Data_Get_Struct(klass, struct jvi_data, ptr); 132 | if (!(*jenv)->IsInstanceOf(jenv, ptr->obj, rjb_j_throwable)) 133 | { 134 | rb_raise(rb_eRuntimeError, "arg1 must be a throwable"); 135 | } 136 | else 137 | { 138 | (*jenv)->Throw(jenv, ptr->obj); 139 | } 140 | } 141 | return Qnil; 142 | } 143 | 144 | void rjb_check_exception(JNIEnv* jenv, int t) 145 | { 146 | jthrowable exp = (*jenv)->ExceptionOccurred(jenv); 147 | if (exp) 148 | { 149 | VALUE rexp = Qnil; 150 | if (RTEST(ruby_verbose)) 151 | { 152 | (*jenv)->ExceptionDescribe(jenv); 153 | } 154 | (*jenv)->ExceptionClear(jenv); 155 | if(1) 156 | { 157 | char* msg = (char*)"unknown exception"; 158 | jclass cls = (*jenv)->GetObjectClass(jenv, exp); 159 | jstring str = (*jenv)->CallObjectMethod(jenv, exp, rjb_throwable_getMessage); 160 | if (str) 161 | { 162 | const char* p = (*jenv)->GetStringUTFChars(jenv, str, JNI_FALSE); 163 | msg = ALLOCA_N(char, strlen(p) + 1); 164 | strcpy(msg, p); 165 | rjb_release_string(jenv, str, p); 166 | } 167 | str = (*jenv)->CallObjectMethod(jenv, cls, rjb_class_getName); 168 | if (str) 169 | { 170 | rexp = rjb_get_exception_class(jenv, str); 171 | } 172 | if (rexp == Qnil) 173 | { 174 | (*jenv)->DeleteLocalRef(jenv, exp); 175 | rb_raise(rb_eRuntimeError, "%s", msg); 176 | } 177 | else 178 | { 179 | VALUE rexpi = rb_funcall(rexp, rb_intern("new"), 1, rb_str_new2(msg)); 180 | jvalue val; 181 | val.l = exp; 182 | rb_ivar_set(rexpi, rb_intern("@cause"), jv2rv(jenv, val)); 183 | rb_exc_raise(rexpi); 184 | } 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /lib/rjb.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | Copyright(c) 2006-2010,2012,2020 arton 3 | =end 4 | 5 | require 'rbconfig' 6 | 7 | begin 8 | require 'rubinius/ffi' 9 | module DL 10 | extend FFI::Library 11 | class FakeDL 12 | def initialize(lib) 13 | @lib = lib 14 | end 15 | def [](fun) 16 | f = @lib.find_function(fun) 17 | if f 18 | f.to_i 19 | else 20 | nil 21 | end 22 | end 23 | end 24 | def self.dlopen(lib) 25 | a = ffi_lib(lib) 26 | if Array === a && a.size >= 1 27 | FakeDL.new(a[0]) 28 | else 29 | nil 30 | end 31 | end 32 | end 33 | rescue LoadError 34 | end 35 | 36 | module RjbConf 37 | if /darwin/ =~ RUBY_PLATFORM 38 | if ENV['JVM_LIB'].nil? || ENV['JVM_LIB'] == '' 39 | if ENV['JAVA_HOME'].nil? || ENV['JAVA_HOME'] == '' 40 | jvms = Dir.glob("#{`/usr/libexec/java_home`.strip}/**/libjvm.dylib") 41 | else 42 | jvms = Dir.glob("#{ENV['JAVA_HOME']}/**/libjvm.dylib") 43 | end 44 | if jvms.size > 0 45 | ENV['JVM_LIB'] = jvms[0] 46 | end 47 | end 48 | elsif /win32|win64/ =~ RUBY_PLATFORM 49 | # add JRE bin directory for further DLLs 50 | ENV['PATH'] = "#{ENV['JAVA_HOME']}\\jre\\bin;#{ENV['PATH']}" 51 | end 52 | 53 | dir = File.join(File.dirname(File.dirname(__FILE__)), 'data') 54 | if File.exist?(dir) 55 | datadir = dir 56 | else 57 | datadir = RbConfig::CONFIG['datadir'] 58 | end 59 | BRIDGE_FILE = File.join(datadir, 'rjb', 'jp', 'co', 'infoseek', 'hp', 60 | 'arton', 'rjb', 'RBridge.class') 61 | unless File.exist?(BRIDGE_FILE) 62 | raise 'bridge file not found' 63 | end 64 | end 65 | 66 | require 'rjbcore' 67 | 68 | module Rjb 69 | def self.import(cls) 70 | s_import(cls) 71 | rescue NoSuchFieldError => e 72 | puts "#{cls}: #{e.inspect}" if $VERBOSE 73 | s_import(cls) 74 | end 75 | 76 | def import(cls) 77 | s_import(cls) 78 | rescue NoSuchFieldError => e 79 | puts "#{cls}: #{e.inspect}" if $VERBOSE 80 | s_import(cls) 81 | end 82 | 83 | module MODIFIER 84 | def self.STATIC 85 | 8 86 | end 87 | def self.PUBLIC 88 | 1 89 | end 90 | end 91 | 92 | module JMethod 93 | def instance_method?(m) 94 | m.modifiers & MODIFIER.STATIC == 0 95 | end 96 | def public_method?(m) 97 | (m.modifiers & MODIFIER.PUBLIC) == MODIFIER.PUBLIC 98 | end 99 | def jmethods(org, klass, &blk) 100 | (org + klass.getMethods.select do |m| 101 | blk.call(m) 102 | end.map do |m| 103 | m.name.to_sym 104 | end).uniq 105 | end 106 | def format_sigs(s) 107 | if s.size < 0 108 | '' 109 | elsif s.size == 1 110 | s[0] 111 | else 112 | "[#{s.map{|m|m.nil? ? 'void' : m}.join(', ')}]" 113 | end 114 | end 115 | def make_snake(nm) 116 | nm.gsub(/(.)([A-Z])/) { "#{$1}_#{$2.downcase}" } 117 | end 118 | alias :rjb_org_respond_to? :respond_to? 119 | def rjb_respond_to?(sym, klass, priv) 120 | return true if (klass ? self : getClass).getMethods.select do |m| 121 | (klass && !instance_method?(m) && (priv || public_method?(m))) || 122 | (!klass && instance_method?(m) && (priv || public_method?(m))) 123 | end.map do |m| 124 | [m.name.to_sym, make_snake(m.name).to_sym] 125 | end.flatten.include?(sym.to_sym) 126 | rjb_org_respond_to?(sym, priv) 127 | end 128 | end 129 | 130 | class Rjb_JavaClass 131 | include JMethod 132 | def public_methods(inh = true) 133 | jmethods(super(inh), self) do |m| 134 | !instance_method?(m) && public_method?(m) 135 | end 136 | end 137 | def methods(inh = true) 138 | jmethods(super(inh), self) do |m| 139 | !instance_method?(m) && public_method?(m) 140 | end 141 | end 142 | def java_methods 143 | jmethods([], self) do |m| 144 | !instance_method?(m) && public_method?(m) 145 | end.map do |m| 146 | "#{m}(#{format_sigs(self.static_sigs(m))})" 147 | end 148 | end 149 | def respond_to?(sym, priv = false) 150 | rjb_respond_to?(sym, true, priv) 151 | end 152 | end 153 | class Rjb_JavaProxy 154 | include JMethod 155 | def initialize_proxy 156 | end 157 | def public_methods(inh = true) 158 | jmethods(super(inh), getClass) do |m| 159 | instance_method?(m) && public_method?(m) 160 | end 161 | end 162 | def methods(inh = true) 163 | jmethods(super(inh), getClass) do |m| 164 | instance_method?(m) && public_method?(m) 165 | end 166 | end 167 | def java_methods 168 | jmethods([], getClass) do |m| 169 | instance_method?(m) && public_method?(m) 170 | end.map do |m| 171 | "#{m}(#{format_sigs(getClass.sigs(m))})" 172 | end 173 | end 174 | def respond_to?(sym, priv = false) 175 | rjb_respond_to?(sym, false, priv) 176 | end 177 | end 178 | class Rjb_JavaBridge 179 | def method_missing(name, *args) 180 | @wrapped.__send__(name, *args) 181 | end 182 | def respond_to?(name, inc_private = false) 183 | @wrapped.respond_to?(name, inc_private) 184 | end 185 | attr_reader :wrapped 186 | end 187 | end 188 | -------------------------------------------------------------------------------- /lib/rjb/extension.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | Copyright(c) 2010 arton 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | $Id: rjbextension.rb 147 2010-10-23 05:10:33Z arton $ 15 | 16 | This file is from Andreas Ronge project neo4j 17 | http://github.com/andreasronge/neo4j/blob/rjb/lib/rjb_ext.rb 18 | 19 | Copyright (c) 2008 Andreas Ronge 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in 29 | all copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 37 | THE SOFTWARE. 38 | =end 39 | 40 | # Loads the JVM with the given classpath and arguments to the jre. 41 | # All needed .jars should be included in classpath. 42 | 43 | module Kernel 44 | alias rjb_original_require require 45 | 46 | def require(path) 47 | rjb_original_require(path) 48 | rescue LoadError 49 | # check that it's not a jar file 50 | raise unless path =~ /\.jar/ 51 | 52 | # This will maybe use the wrong jar file from a previous version of the GEM 53 | # puts "LOAD PATH #{$LOAD_PATH}" 54 | if File.respond_to?(:absolute_path?) && File.absolute_path?(path) 55 | found_path = File.exist?(path) ? '' : nil 56 | else 57 | found_path = $LOAD_PATH.reverse.find {|p| File.exist?(File.join(p, path))} 58 | end 59 | raise unless found_path 60 | 61 | abs_path = found_path.length == 0 ? path : File.join(found_path, path) 62 | # check that the file exists 63 | raise unless File.exist?(abs_path) 64 | 65 | # try to load it using RJB 66 | if Rjb::loaded? 67 | Rjb::add_jar abs_path 68 | else 69 | Rjb::add_classpath abs_path 70 | end 71 | end 72 | 73 | def load_jvm(jargs = []) 74 | return if Rjb::loaded? 75 | classpath = ENV['CLASSPATH'] ||= '' 76 | Rjb::load(classpath, jargs) 77 | end 78 | end 79 | 80 | class JavaPackage 81 | 82 | def initialize(pack_name, parent_pack = nil) 83 | @pack_name = pack_name 84 | @parent_pack = parent_pack 85 | @cache = {} 86 | end 87 | 88 | def method_missing(m, *args) 89 | # return if possible old module/class 90 | @cache[m] ||= create_package_or_class(m) 91 | end 92 | def create_package_or_class(m) 93 | method = m.to_s 94 | if class?(method) 95 | Rjb::import("#{self}.#{method}") 96 | else 97 | JavaPackage.new(method, self) 98 | end 99 | end 100 | 101 | def to_s 102 | if @parent_pack 103 | "#{@parent_pack.to_s}.#@pack_name" 104 | else 105 | "#@pack_name" 106 | end 107 | end 108 | 109 | def class?(a) 110 | first_letter = a[0,1] 111 | first_letter >= 'A' && first_letter <= 'Z' 112 | end 113 | 114 | @@cache = {} 115 | def self.new(pack_name, parent_pack = nil) 116 | @@cache[pack_name] ||= super 117 | end 118 | end 119 | 120 | module RjbConf 121 | # make them as singleton 122 | ORG = JavaPackage.new('org') 123 | JAVA = JavaPackage.new('java') 124 | end 125 | 126 | def org 127 | RjbConf::ORG 128 | end 129 | 130 | def java 131 | RjbConf::JAVA 132 | end 133 | -------------------------------------------------------------------------------- /lib/rjb/list.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | =begin 3 | Copyright(c) 2012 arton 4 | =end 5 | 6 | require 'rjb' 7 | 8 | module Rjb 9 | JIterable = import('java.lang.Iterable') 10 | JIterator = import('java.util.Iterator') 11 | module Iterable 12 | def each 13 | it = iterator 14 | while it.has_next 15 | yield it.next 16 | end 17 | end 18 | end 19 | module Iterator 20 | def each 21 | while has_next 22 | yield self.next 23 | end 24 | end 25 | end 26 | class Rjb_JavaProxy 27 | def initialize_proxy 28 | if JIterable.isInstance(self) 29 | include Iterable 30 | include Enumerable 31 | elsif JIterator.isInstance(self) 32 | include Iterator 33 | include Enumerable 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/rjb/version.rb: -------------------------------------------------------------------------------- 1 | module Rjb 2 | class << self 3 | 4 | private 5 | 6 | # @return [String, nil] the valid version number. Can be nil. 7 | def read_version 8 | path = File.expand_path('../../../ext/rjb.c', __FILE__) 9 | File.open(path) do |f| 10 | f.each_line do |l| 11 | m = /RJB_VERSION\s+"(.+?)"/.match(l) 12 | 13 | # The file is closed even in this case. 14 | return m[1] if m 15 | end 16 | end 17 | end 18 | end 19 | 20 | # The `Rjb` module defines `VERSION` in the C code. 21 | # If Rjb is already required we have the constant. 22 | unless defined?(::Rjb::VERSION) 23 | unless (VERSION = read_version) 24 | raise 'Cannot find a valid version number in `rjb.c`!' 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/rjbextension.rb: -------------------------------------------------------------------------------- 1 | require 'rjb/extension' 2 | -------------------------------------------------------------------------------- /pre-install.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | Copyright (c) 2006,2014 arton 3 | =end 4 | 5 | require 'rbconfig' 6 | 7 | if File.exist?(File.join(RbConfig::CONFIG['sitearchdir'], 'rjb.so')) 8 | File.delete(File.join(RbConfig::CONFIG['sitearchdir'], 'rjb.so')) 9 | end 10 | 11 | -------------------------------------------------------------------------------- /readme.sj: -------------------------------------------------------------------------------- 1 | 準備 2 | ・あらかじめ環境変数にJAVA_HOMEを設定しておいてください。 3 | ・この場合、JAVA_HOMEは、J2SDKのインストールディレクトリの必要があります。 4 | ・あらかじめ環境変数PATHに$JAVA_HOME/binを設定しておいてください。 5 | ・Windowsの場合、PATHには%PATH%;%JAVA_HOME%binを設定することになります。 6 | ・ruby1.8以降が実行できるようにPATHを設定しておいてください。 7 | 8 | インストール方法 9 | 1. unzip rjb-* 10 | 2. cd rjb-* 11 | 3. ruby setup.rb config 12 | 4. ruby setup.rb setup 13 | 5. sudo ruby setup.rb install 14 | Windowsでは、ほとんどの場合最初のsudoは不要です。「ほとんどの場合」に該当しない場合は何が必要かはわかっているはずですので説明は省略します。 15 | 16 | 実行時 17 | ・あらかじめ環境変数にJAVA_HOMEを設定しておいてください。 18 | ・この場合、JAVA_HOMEは、J2SDKのインストールディレクトリの必要があります。 19 | ・Linuxに関してはLD_LIBRARY_PATHに、java2の共有オブジェクトディレクトリを設定しておく必要があります。 20 | 21 | テストした環境 22 | Windows2000 SP4-ruby1.8.2-j2se1.5.0, Solaris9-ruby1.8.0-j2se1.4.2, Linux 2.4.26-ruby-1.8.1-j2se1.4.2 23 | 24 | 連絡先 25 | artonx@yahoo.co.jp 26 | https://www.artonx.org/collabo/backyard/?RjbQandA (記入時にはdiaryへツッコミを入れてください) 27 | 28 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Rjb is Ruby-Java bridge using Java Native Interface. 2 | 3 | http://www.slideshare.net/artonx/j-ruby-kaigi-2010 4 | 5 | How to install 6 | 7 | you need to install Java2 sdk, and setup JAVA_HOME enviromental varible except for OS X. 8 | I assume that OS X's JAVA_HOME is reported by calling /usr/libexec/java_home. 9 | 10 | then, 11 | 12 | ruby setup.rb config 13 | ruby setup.rb setup 14 | 15 | (in Unix) 16 | sudo ruby setup.rb install 17 | or 18 | (in win32) 19 | ruby setup.rb install 20 | 21 | How to test 22 | in Win32 23 | cd test 24 | ruby test.rb 25 | 26 | in Unix 27 | see test/readme.unix 28 | you must set LD_LIBRARY_PATH environmental variable to run rjb. 29 | 30 | -- Notice for opening non-ASCII 7bit filename 31 | If you'll plan to open the non-ascii character named file by Java class through Rjb, it may require to set LC_ALL environment variable in your script. 32 | For example in Rails, set above line in production.rb as your environment. 33 | ENV['LC_ALL'] = 'en_us.utf8' # or ja_JP.utf8 etc. 34 | cf: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4733494 35 | (Thanks Paul for this information). 36 | 37 | artonx@yahoo.co.jp 38 | -------------------------------------------------------------------------------- /rjb.gemspec: -------------------------------------------------------------------------------- 1 | lib_path = File.expand_path(File.join(File.dirname(__FILE__), 'lib')) 2 | $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path) 3 | 4 | require 'rake' 5 | require 'rjb/version' 6 | 7 | RJB_GEMSPEC = Gem::Specification.new do |s| 8 | s.author = 'arton' 9 | s.email = 'artonx@gmail.com' 10 | s.name = 'rjb' 11 | s.description = 'RJB is a Bridge library which connects Ruby and Java'\ 12 | ' code using the Java Native Interface.' 13 | s.summary = 'Ruby Java Bridge' 14 | s.homepage = 'http://www.artonx.org/collabo/backyard/?RubyJavaBridge' 15 | s.version = Rjb::VERSION 16 | s.require_path = 'lib' 17 | # @todo We need a meaningful explanation for the end user. 18 | s.requirements << 'JDK 5.0' 19 | s.license = 'LGPL-2.1-or-later' 20 | # @todo Do we need to support these old versions? 21 | s.required_ruby_version = '>= 1.8.2' 22 | # @todo Do we really need all the source code? 23 | s.files = FileList['ext/*.java', 'ext/*.c', 'ext/*.h', 'ext/depend.erb', 24 | 'data/rjb/**/*.class', 'lib/*.rb', 'lib/rjb/*.rb', 25 | 'samples/**/*.rb', 'test/*.rb', 'test/**/*.class', 26 | 'test/*.jar', 'COPYING', 'ChangeLog', 'readme.*', 27 | 'README.md'] 28 | 29 | # @todo We need some restrictions for JRuby and other plattforms 30 | # following RbConfig::CONFIG['host_os'] definitions. 31 | # A possible better solution is `rake-compiler`. 32 | case RUBY_PLATFORM 33 | when /mswin/ 34 | s.platform = Gem::Platform::CURRENT 35 | FileUtils.cp 'ext/rjbcore.so', 'lib/rjbcore.so' 36 | s.files << 'lib/rjbcore.so' 37 | # @todo We need a meaningful explanation for the end user. 38 | s.requirements << 'VC6 version of Ruby' 39 | when /mingw/ 40 | s.platform = Gem::Platform::CURRENT 41 | FileUtils.cp 'ext/rjbcore.so', 'lib/rjbcore.so' 42 | s.files << 'lib/rjbcore.so' 43 | when /darwin/ 44 | s.platform = Gem::Platform::CURRENT 45 | FileUtils.cp 'ext/rjbcore.bundle', 'lib/rjbcore.bundle' 46 | s.files << 'lib/rjbcore.bundle' 47 | else 48 | s.platform = Gem::Platform::RUBY 49 | s.extensions << 'ext/extconf.rb' 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /rjb.rake: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | begin 3 | require 'rake/gempackagetask' 4 | $package_task = Rake::GemPackageTask 5 | rescue LoadError 6 | require 'rubygems/package_task' 7 | $package_task = Gem::PackageTask 8 | end 9 | require 'fileutils' 10 | 11 | def read_version 12 | File.open('ext/rjb.c').each_line do |x| 13 | m = /RJB_VERSION\s+"(.+?)"/.match(x) 14 | if m 15 | return m[1] 16 | end 17 | end 18 | nil 19 | end 20 | 21 | desc "Default Task" 22 | task :default => [ :package ] 23 | 24 | spec = Gem::Specification.new do |s| 25 | s.authors = 'arton' 26 | s.email = 'artonx@gmail.com' 27 | if /mswin|mingw|darwin/ =~ RUBY_PLATFORM 28 | s.platform = Gem::Platform::CURRENT 29 | else 30 | s.platform = Gem::Platform::RUBY 31 | s.extensions << 'ext/extconf.rb' 32 | end 33 | s.required_ruby_version = '>= 1.8.2' 34 | s.summary = 'Ruby Java bridge' 35 | s.name = 'rjb' 36 | s.homepage = 'https://www.artonx.org/collabo/backyard/?RubyJavaBridge' 37 | s.version = read_version 38 | s.requirements << 'none' 39 | s.require_path = 'lib' 40 | s.requirements << 'JDK 5.0' 41 | s.license = 'LGPL-2.1-or-later' 42 | files = FileList['ext/*.java', 'ext/*.c', 'ext/*.h', 'ext/depend.erb', 43 | 'data/rjb/**/*.class', 'lib/*.rb', 'lib/rjb/*.rb', 'samples/**/*.rb', 44 | 'test/*.rb', 'test/**/*.class', 'test/*.jar', 'COPYING', 'ChangeLog', 'readme.*'] 45 | if /mswin|mingw/ =~ RUBY_PLATFORM 46 | FileUtils.cp 'ext/rjbcore.so', 'lib/rjbcore.so' 47 | files << "lib/rjbcore.so" 48 | s.requirements << ' VC6 version of Ruby' if RUBY_PLATFORM =~ /mswin/ 49 | elsif /darwin/ =~ RUBY_PLATFORM 50 | FileUtils.cp 'ext/rjbcore.bundle', 'lib/rjbcore.bundle' 51 | files << "lib/rjbcore.bundle" 52 | end 53 | s.files = files 54 | s.test_file = 'test/test.rb' 55 | s.description = <) { table[$1] } 86 | end 87 | 88 | def set(val) 89 | @value = check(val) 90 | end 91 | 92 | private 93 | 94 | def check(val) 95 | setup_rb_error "config: --#{name} requires argument" unless val 96 | val 97 | end 98 | end 99 | 100 | class BoolItem < ConfigItem 101 | def config_type 102 | 'bool' 103 | end 104 | 105 | def help_opt 106 | "--#{@name}" 107 | end 108 | 109 | private 110 | 111 | def check(val) 112 | return 'yes' unless val 113 | unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val 114 | setup_rb_error "config: --#{@name} accepts only yes/no for argument" 115 | end 116 | (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no' 117 | end 118 | end 119 | 120 | class PathItem < ConfigItem 121 | def config_type 122 | 'path' 123 | end 124 | 125 | private 126 | 127 | def check(path) 128 | setup_rb_error "config: --#{@name} requires argument" unless path 129 | path[0,1] == '$' ? path : File.expand_path(path) 130 | end 131 | end 132 | 133 | class ProgramItem < ConfigItem 134 | def config_type 135 | 'program' 136 | end 137 | end 138 | 139 | class SelectItem < ConfigItem 140 | def initialize(name, template, default, desc) 141 | super 142 | @ok = template.split('/') 143 | end 144 | 145 | def config_type 146 | 'select' 147 | end 148 | 149 | private 150 | 151 | def check(val) 152 | unless @ok.include?(val.strip) 153 | setup_rb_error "config: use --#{@name}=#{@template} (#{val})" 154 | end 155 | val.strip 156 | end 157 | end 158 | 159 | class PackageSelectionItem < ConfigItem 160 | def initialize(name, template, default, help_default, desc) 161 | super name, template, default, desc 162 | @help_default = help_default 163 | end 164 | 165 | attr_reader :help_default 166 | 167 | def config_type 168 | 'package' 169 | end 170 | 171 | private 172 | 173 | def check(val) 174 | unless File.dir?("packages/#{val}") 175 | setup_rb_error "config: no such package: #{val}" 176 | end 177 | val 178 | end 179 | end 180 | 181 | class ConfigTable_class 182 | 183 | def initialize(items) 184 | @items = items 185 | @table = {} 186 | items.each do |i| 187 | @table[i.name] = i 188 | end 189 | ALIASES.each do |ali, name| 190 | @table[ali] = @table[name] 191 | end 192 | end 193 | 194 | include Enumerable 195 | 196 | def each(&block) 197 | @items.each(&block) 198 | end 199 | 200 | def key?(name) 201 | @table.key?(name) 202 | end 203 | 204 | def lookup(name) 205 | @table[name] or raise ArgumentError, "no such config item: #{name}" 206 | end 207 | 208 | def add(item) 209 | @items.push item 210 | @table[item.name] = item 211 | end 212 | 213 | def remove(name) 214 | item = lookup(name) 215 | @items.delete_if {|i| i.name == name } 216 | @table.delete_if {|name, i| i.name == name } 217 | item 218 | end 219 | 220 | def new 221 | dup() 222 | end 223 | 224 | def savefile 225 | '.config' 226 | end 227 | 228 | def load 229 | begin 230 | t = dup() 231 | File.foreach(savefile()) do |line| 232 | k, v = *line.split(/=/, 2) 233 | t[k] = v.strip 234 | end 235 | t 236 | rescue Errno::ENOENT 237 | setup_rb_error $!.message + "#{File.basename($0)} config first" 238 | end 239 | end 240 | 241 | def save 242 | @items.each {|i| i.value } 243 | File.open(savefile(), 'w') {|f| 244 | @items.each do |i| 245 | f.printf "%s=%s\n", i.name, i.value if i.value 246 | end 247 | } 248 | end 249 | 250 | def [](key) 251 | lookup(key).eval(self) 252 | end 253 | 254 | def []=(key, val) 255 | lookup(key).set val 256 | end 257 | 258 | end 259 | 260 | c = ::RbConfig::CONFIG 261 | 262 | rubypath = c['bindir'] + '/' + c['ruby_install_name'] 263 | 264 | major = c['MAJOR'].to_i 265 | minor = c['MINOR'].to_i 266 | teeny = c['TEENY'].to_i 267 | version = "#{major}.#{minor}" 268 | 269 | # ruby ver. >= 1.4.4? 270 | newpath_p = ((major >= 2) or 271 | ((major == 1) and 272 | ((minor >= 5) or 273 | ((minor == 4) and (teeny >= 4))))) 274 | 275 | if c['rubylibdir'] 276 | # V < 1.6.3 277 | _stdruby = c['rubylibdir'] 278 | _siteruby = c['sitedir'] 279 | _siterubyver = c['sitelibdir'] 280 | _siterubyverarch = c['sitearchdir'] 281 | elsif newpath_p 282 | # 1.4.4 <= V <= 1.6.3 283 | _stdruby = "$prefix/lib/ruby/#{version}" 284 | _siteruby = c['sitedir'] 285 | _siterubyver = "$siteruby/#{version}" 286 | _siterubyverarch = "$siterubyver/#{c['arch']}" 287 | else 288 | # V < 1.4.4 289 | _stdruby = "$prefix/lib/ruby/#{version}" 290 | _siteruby = "$prefix/lib/ruby/#{version}/site_ruby" 291 | _siterubyver = _siteruby 292 | _siterubyverarch = "$siterubyver/#{c['arch']}" 293 | end 294 | libdir = '-* dummy libdir *-' 295 | stdruby = '-* dummy rubylibdir *-' 296 | siteruby = '-* dummy site_ruby *-' 297 | siterubyver = '-* dummy site_ruby version *-' 298 | parameterize = lambda {|path| 299 | path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\ 300 | .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\ 301 | .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\ 302 | .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\ 303 | .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver') 304 | } 305 | libdir = parameterize.call(c['libdir']) 306 | stdruby = parameterize.call(_stdruby) 307 | siteruby = parameterize.call(_siteruby) 308 | siterubyver = parameterize.call(_siterubyver) 309 | siterubyverarch = parameterize.call(_siterubyverarch) 310 | 311 | if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } 312 | makeprog = arg.sub(/'/, '').split(/=/, 2)[1] 313 | else 314 | makeprog = 'make' 315 | end 316 | 317 | common_conf = [ 318 | PathItem.new('prefix', 'path', c['prefix'], 319 | 'path prefix of target environment'), 320 | PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 321 | 'the directory for commands'), 322 | PathItem.new('libdir', 'path', libdir, 323 | 'the directory for libraries'), 324 | PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 325 | 'the directory for shared data'), 326 | PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 327 | 'the directory for man pages'), 328 | PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 329 | 'the directory for man pages'), 330 | PathItem.new('stdruby', 'path', stdruby, 331 | 'the directory for standard ruby libraries'), 332 | PathItem.new('siteruby', 'path', siteruby, 333 | 'the directory for version-independent aux ruby libraries'), 334 | PathItem.new('siterubyver', 'path', siterubyver, 335 | 'the directory for aux ruby libraries'), 336 | PathItem.new('siterubyverarch', 'path', siterubyverarch, 337 | 'the directory for aux ruby binaries'), 338 | PathItem.new('rbdir', 'path', '$siterubyver', 339 | 'the directory for ruby scripts'), 340 | PathItem.new('sodir', 'path', '$siterubyverarch', 341 | 'the directory for ruby extentions'), 342 | PathItem.new('rubypath', 'path', rubypath, 343 | 'the path to set to #! line'), 344 | ProgramItem.new('rubyprog', 'name', rubypath, 345 | 'the ruby program using for installation'), 346 | ProgramItem.new('makeprog', 'name', makeprog, 347 | 'the make program to compile ruby extentions'), 348 | SelectItem.new('shebang', 'all/ruby/never', 'ruby', 349 | 'shebang line (#!) editing mode'), 350 | BoolItem.new('without-ext', 'yes/no', 'no', 351 | 'does not compile/install ruby extentions') 352 | ] 353 | class ConfigTable_class # open again 354 | ALIASES = { 355 | 'std-ruby' => 'stdruby', 356 | 'site-ruby-common' => 'siteruby', # For backward compatibility 357 | 'site-ruby' => 'siterubyver', # For backward compatibility 358 | 'bin-dir' => 'bindir', 359 | 'rb-dir' => 'rbdir', 360 | 'so-dir' => 'sodir', 361 | 'data-dir' => 'datadir', 362 | 'ruby-path' => 'rubypath', 363 | 'ruby-prog' => 'rubyprog', 364 | 'ruby' => 'rubyprog', 365 | 'make-prog' => 'makeprog', 366 | 'make' => 'makeprog' 367 | } 368 | end 369 | multipackage_conf = [ 370 | PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 371 | 'package names that you want to install'), 372 | PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 373 | 'package names that you do not want to install') 374 | ] 375 | if multipackage_install? 376 | ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf) 377 | else 378 | ConfigTable = ConfigTable_class.new(common_conf) 379 | end 380 | 381 | 382 | module MetaConfigAPI 383 | 384 | def eval_file_ifexist(fname) 385 | instance_eval File.read(fname), fname, 1 if File.file?(fname) 386 | end 387 | 388 | def config_names 389 | ConfigTable.map {|i| i.name } 390 | end 391 | 392 | def config?(name) 393 | ConfigTable.key?(name) 394 | end 395 | 396 | def bool_config?(name) 397 | ConfigTable.lookup(name).config_type == 'bool' 398 | end 399 | 400 | def path_config?(name) 401 | ConfigTable.lookup(name).config_type == 'path' 402 | end 403 | 404 | def value_config?(name) 405 | case ConfigTable.lookup(name).config_type 406 | when 'bool', 'path' 407 | true 408 | else 409 | false 410 | end 411 | end 412 | 413 | def add_config(item) 414 | ConfigTable.add item 415 | end 416 | 417 | def add_bool_config(name, default, desc) 418 | ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) 419 | end 420 | 421 | def add_path_config(name, default, desc) 422 | ConfigTable.add PathItem.new(name, 'path', default, desc) 423 | end 424 | 425 | def set_config_default(name, default) 426 | ConfigTable.lookup(name).default = default 427 | end 428 | 429 | def remove_config(name) 430 | ConfigTable.remove(name) 431 | end 432 | 433 | end 434 | 435 | 436 | # 437 | # File Operations 438 | # 439 | 440 | module FileOperations 441 | 442 | def mkdir_p(dirname, prefix = nil) 443 | dirname = prefix + File.expand_path(dirname) if prefix 444 | $stderr.puts "mkdir -p #{dirname}" if verbose? 445 | return if no_harm? 446 | 447 | # does not check '/'... it's too abnormal case 448 | dirs = File.expand_path(dirname).split(%r<(?=/)>) 449 | if /\A[a-z]:\z/i =~ dirs[0] 450 | disk = dirs.shift 451 | dirs[0] = disk + dirs[0] 452 | end 453 | dirs.each_index do |idx| 454 | path = dirs[0..idx].join('') 455 | Dir.mkdir path unless File.dir?(path) 456 | end 457 | end 458 | 459 | def rm_f(fname) 460 | $stderr.puts "rm -f #{fname}" if verbose? 461 | return if no_harm? 462 | 463 | if File.exist?(fname) or File.symlink?(fname) 464 | File.chmod 0777, fname 465 | File.unlink fname 466 | end 467 | end 468 | 469 | def rm_rf(dn) 470 | $stderr.puts "rm -rf #{dn}" if verbose? 471 | return if no_harm? 472 | 473 | Dir.chdir dn 474 | Dir.foreach('.') do |fn| 475 | next if fn == '.' 476 | next if fn == '..' 477 | if File.dir?(fn) 478 | verbose_off { 479 | rm_rf fn 480 | } 481 | else 482 | verbose_off { 483 | rm_f fn 484 | } 485 | end 486 | end 487 | Dir.chdir '..' 488 | Dir.rmdir dn 489 | end 490 | 491 | def move_file(src, dest) 492 | File.unlink dest if File.exist?(dest) 493 | begin 494 | File.rename src, dest 495 | rescue 496 | File.open(dest, 'wb') {|f| f.write File.binread(src) } 497 | File.chmod File.stat(src).mode, dest 498 | File.unlink src 499 | end 500 | end 501 | 502 | def install(from, dest, mode, prefix = nil) 503 | $stderr.puts "install #{from} #{dest}" if verbose? 504 | return if no_harm? 505 | 506 | realdest = prefix ? prefix + File.expand_path(dest) : dest 507 | realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) 508 | str = File.binread(from) 509 | if diff?(str, realdest) 510 | verbose_off { 511 | rm_f realdest if File.exist?(realdest) 512 | } 513 | File.open(realdest, 'wb') {|f| 514 | f.write str 515 | } 516 | File.chmod mode, realdest 517 | 518 | File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| 519 | if prefix 520 | f.puts realdest.sub(prefix, '') 521 | else 522 | f.puts realdest 523 | end 524 | } 525 | end 526 | end 527 | 528 | def diff?(new_content, path) 529 | return true unless File.exist?(path) 530 | new_content != File.binread(path) 531 | end 532 | 533 | def command(str) 534 | $stderr.puts str if verbose? 535 | system str or raise RuntimeError, "'system #{str}' failed" 536 | end 537 | 538 | def ruby(str) 539 | command config('rubyprog') + ' ' + str 540 | end 541 | 542 | def make(task = '') 543 | command config('makeprog') + ' ' + task 544 | end 545 | 546 | def extdir?(dir) 547 | File.exist?(dir + '/MANIFEST') 548 | end 549 | 550 | def all_files_in(dirname) 551 | Dir.open(dirname) {|d| 552 | return d.select {|ent| File.file?("#{dirname}/#{ent}") } 553 | } 554 | end 555 | 556 | REJECT_DIRS = %w( 557 | CVS SCCS RCS CVS.adm .svn 558 | ) 559 | 560 | def all_dirs_in(dirname) 561 | Dir.open(dirname) {|d| 562 | return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS 563 | } 564 | end 565 | 566 | end 567 | 568 | 569 | # 570 | # Main Installer 571 | # 572 | 573 | module HookUtils 574 | 575 | def run_hook(name) 576 | try_run_hook "#{curr_srcdir()}/#{name}" or 577 | try_run_hook "#{curr_srcdir()}/#{name}.rb" 578 | end 579 | 580 | def try_run_hook(fname) 581 | return false unless File.file?(fname) 582 | begin 583 | instance_eval File.read(fname), fname, 1 584 | rescue 585 | setup_rb_error "hook #{fname} failed:\n" + $!.message 586 | end 587 | true 588 | end 589 | 590 | end 591 | 592 | 593 | module HookScriptAPI 594 | 595 | def get_config(key) 596 | @config[key] 597 | end 598 | 599 | alias config get_config 600 | 601 | def set_config(key, val) 602 | @config[key] = val 603 | end 604 | 605 | # 606 | # srcdir/objdir (works only in the package directory) 607 | # 608 | 609 | #abstract srcdir_root 610 | #abstract objdir_root 611 | #abstract relpath 612 | 613 | def curr_srcdir 614 | "#{srcdir_root()}/#{relpath()}" 615 | end 616 | 617 | def curr_objdir 618 | "#{objdir_root()}/#{relpath()}" 619 | end 620 | 621 | def srcfile(path) 622 | "#{curr_srcdir()}/#{path}" 623 | end 624 | 625 | def srcexist?(path) 626 | File.exist?(srcfile(path)) 627 | end 628 | 629 | def srcdirectory?(path) 630 | File.dir?(srcfile(path)) 631 | end 632 | 633 | def srcfile?(path) 634 | File.file? srcfile(path) 635 | end 636 | 637 | def srcentries(path = '.') 638 | Dir.open("#{curr_srcdir()}/#{path}") {|d| 639 | return d.to_a - %w(. ..) 640 | } 641 | end 642 | 643 | def srcfiles(path = '.') 644 | srcentries(path).select {|fname| 645 | File.file?(File.join(curr_srcdir(), path, fname)) 646 | } 647 | end 648 | 649 | def srcdirectories(path = '.') 650 | srcentries(path).select {|fname| 651 | File.dir?(File.join(curr_srcdir(), path, fname)) 652 | } 653 | end 654 | 655 | end 656 | 657 | 658 | class ToplevelInstaller 659 | 660 | Version = '3.3.1' 661 | Copyright = 'Copyright (c) 2000-2004 Minero Aoki' 662 | 663 | TASKS = [ 664 | [ 'all', 'do config, setup, then install' ], 665 | [ 'config', 'saves your configurations' ], 666 | [ 'show', 'shows current configuration' ], 667 | [ 'setup', 'compiles ruby extentions and others' ], 668 | [ 'install', 'installs files' ], 669 | [ 'clean', "does `make clean' for each extention" ], 670 | [ 'distclean',"does `make distclean' for each extention" ] 671 | ] 672 | 673 | def ToplevelInstaller.invoke 674 | instance().invoke 675 | end 676 | 677 | @singleton = nil 678 | 679 | def ToplevelInstaller.instance 680 | @singleton ||= new(File.dirname($0)) 681 | @singleton 682 | end 683 | 684 | include MetaConfigAPI 685 | 686 | def initialize(ardir_root) 687 | @config = nil 688 | @options = { 'verbose' => true } 689 | @ardir = File.expand_path(ardir_root) 690 | end 691 | 692 | def inspect 693 | "#<#{self.class} #{__id__()}>" 694 | end 695 | 696 | def invoke 697 | run_metaconfigs 698 | case task = parsearg_global() 699 | when nil, 'all' 700 | @config = load_config('config') 701 | parsearg_config 702 | init_installers 703 | exec_config 704 | exec_setup 705 | exec_install 706 | else 707 | @config = load_config(task) 708 | __send__ "parsearg_#{task}" 709 | init_installers 710 | __send__ "exec_#{task}" 711 | end 712 | end 713 | 714 | def run_metaconfigs 715 | eval_file_ifexist "#{@ardir}/metaconfig" 716 | end 717 | 718 | def load_config(task) 719 | case task 720 | when 'config' 721 | ConfigTable.new 722 | when 'clean', 'distclean' 723 | if File.exist?(ConfigTable.savefile) 724 | then ConfigTable.load 725 | else ConfigTable.new 726 | end 727 | else 728 | ConfigTable.load 729 | end 730 | end 731 | 732 | def init_installers 733 | @installer = Installer.new(@config, @options, @ardir, File.expand_path('.')) 734 | end 735 | 736 | # 737 | # Hook Script API bases 738 | # 739 | 740 | def srcdir_root 741 | @ardir 742 | end 743 | 744 | def objdir_root 745 | '.' 746 | end 747 | 748 | def relpath 749 | '.' 750 | end 751 | 752 | # 753 | # Option Parsing 754 | # 755 | 756 | def parsearg_global 757 | valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/ 758 | 759 | while arg = ARGV.shift 760 | case arg 761 | when /\A\w+\z/ 762 | setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg 763 | return arg 764 | 765 | when '-q', '--quiet' 766 | @options['verbose'] = false 767 | 768 | when '--verbose' 769 | @options['verbose'] = true 770 | 771 | when '-h', '--help' 772 | print_usage $stdout 773 | exit 0 774 | 775 | when '-v', '--version' 776 | puts "#{File.basename($0)} version #{Version}" 777 | exit 0 778 | 779 | when '--copyright' 780 | puts Copyright 781 | exit 0 782 | 783 | else 784 | setup_rb_error "unknown global option '#{arg}'" 785 | end 786 | end 787 | 788 | nil 789 | end 790 | 791 | 792 | def parsearg_no_options 793 | unless ARGV.empty? 794 | setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}" 795 | end 796 | end 797 | 798 | alias parsearg_show parsearg_no_options 799 | alias parsearg_setup parsearg_no_options 800 | alias parsearg_clean parsearg_no_options 801 | alias parsearg_distclean parsearg_no_options 802 | 803 | def parsearg_config 804 | re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/ 805 | @options['config-opt'] = [] 806 | 807 | while i = ARGV.shift 808 | if /\A--?\z/ =~ i 809 | @options['config-opt'] = ARGV.dup 810 | break 811 | end 812 | m = re.match(i) or setup_rb_error "config: unknown option #{i}" 813 | name, value = *m.to_a[1,2] 814 | @config[name] = value 815 | end 816 | end 817 | 818 | def parsearg_install 819 | @options['no-harm'] = false 820 | @options['install-prefix'] = '' 821 | while a = ARGV.shift 822 | case a 823 | when /\A--no-harm\z/ 824 | @options['no-harm'] = true 825 | when /\A--prefix=(.*)\z/ 826 | path = $1 827 | path = File.expand_path(path) unless path[0,1] == '/' 828 | @options['install-prefix'] = path 829 | else 830 | setup_rb_error "install: unknown option #{a}" 831 | end 832 | end 833 | end 834 | 835 | def print_usage(out) 836 | out.puts 'Typical Installation Procedure:' 837 | out.puts " $ ruby #{File.basename $0} config" 838 | out.puts " $ ruby #{File.basename $0} setup" 839 | out.puts " # ruby #{File.basename $0} install (may require root privilege)" 840 | out.puts 841 | out.puts 'Detailed Usage:' 842 | out.puts " ruby #{File.basename $0} " 843 | out.puts " ruby #{File.basename $0} [] []" 844 | 845 | fmt = " %-24s %s\n" 846 | out.puts 847 | out.puts 'Global options:' 848 | out.printf fmt, '-q,--quiet', 'suppress message outputs' 849 | out.printf fmt, ' --verbose', 'output messages verbosely' 850 | out.printf fmt, '-h,--help', 'print this message' 851 | out.printf fmt, '-v,--version', 'print version and quit' 852 | out.printf fmt, ' --copyright', 'print copyright and quit' 853 | out.puts 854 | out.puts 'Tasks:' 855 | TASKS.each do |name, desc| 856 | out.printf fmt, name, desc 857 | end 858 | 859 | fmt = " %-24s %s [%s]\n" 860 | out.puts 861 | out.puts 'Options for CONFIG or ALL:' 862 | ConfigTable.each do |item| 863 | out.printf fmt, item.help_opt, item.description, item.help_default 864 | end 865 | out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" 866 | out.puts 867 | out.puts 'Options for INSTALL:' 868 | out.printf fmt, '--no-harm', 'only display what to do if given', 'off' 869 | out.printf fmt, '--prefix=path', 'install path prefix', '$prefix' 870 | out.puts 871 | end 872 | 873 | # 874 | # Task Handlers 875 | # 876 | 877 | def exec_config 878 | @installer.exec_config 879 | @config.save # must be final 880 | end 881 | 882 | def exec_setup 883 | @installer.exec_setup 884 | end 885 | 886 | def exec_install 887 | @installer.exec_install 888 | end 889 | 890 | def exec_show 891 | ConfigTable.each do |i| 892 | printf "%-20s %s\n", i.name, i.value 893 | end 894 | end 895 | 896 | def exec_clean 897 | @installer.exec_clean 898 | end 899 | 900 | def exec_distclean 901 | @installer.exec_distclean 902 | end 903 | 904 | end 905 | 906 | 907 | class ToplevelInstallerMulti < ToplevelInstaller 908 | 909 | include HookUtils 910 | include HookScriptAPI 911 | include FileOperations 912 | 913 | def initialize(ardir) 914 | super 915 | @packages = all_dirs_in("#{@ardir}/packages") 916 | raise 'no package exists' if @packages.empty? 917 | end 918 | 919 | def run_metaconfigs 920 | eval_file_ifexist "#{@ardir}/metaconfig" 921 | @packages.each do |name| 922 | eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig" 923 | end 924 | end 925 | 926 | def init_installers 927 | @installers = {} 928 | @packages.each do |pack| 929 | @installers[pack] = Installer.new(@config, @options, 930 | "#{@ardir}/packages/#{pack}", 931 | "packages/#{pack}") 932 | end 933 | 934 | with = extract_selection(config('with')) 935 | without = extract_selection(config('without')) 936 | @selected = @installers.keys.select {|name| 937 | (with.empty? or with.include?(name)) \ 938 | and not without.include?(name) 939 | } 940 | end 941 | 942 | def extract_selection(list) 943 | a = list.split(/,/) 944 | a.each do |name| 945 | setup_rb_error "no such package: #{name}" unless @installers.key?(name) 946 | end 947 | a 948 | end 949 | 950 | def print_usage(f) 951 | super 952 | f.puts 'Inluded packages:' 953 | f.puts ' ' + @packages.sort.join(' ') 954 | f.puts 955 | end 956 | 957 | # 958 | # multi-package metaconfig API 959 | # 960 | 961 | attr_reader :packages 962 | 963 | def declare_packages(list) 964 | raise 'package list is empty' if list.empty? 965 | list.each do |name| 966 | raise "directory packages/#{name} does not exist"\ 967 | unless File.dir?("#{@ardir}/packages/#{name}") 968 | end 969 | @packages = list 970 | end 971 | 972 | # 973 | # Task Handlers 974 | # 975 | 976 | def exec_config 977 | run_hook 'pre-config' 978 | each_selected_installers {|inst| inst.exec_config } 979 | run_hook 'post-config' 980 | @config.save # must be final 981 | end 982 | 983 | def exec_setup 984 | run_hook 'pre-setup' 985 | each_selected_installers {|inst| inst.exec_setup } 986 | run_hook 'post-setup' 987 | end 988 | 989 | def exec_install 990 | run_hook 'pre-install' 991 | each_selected_installers {|inst| inst.exec_install } 992 | run_hook 'post-install' 993 | end 994 | 995 | def exec_clean 996 | rm_f ConfigTable.savefile 997 | run_hook 'pre-clean' 998 | each_selected_installers {|inst| inst.exec_clean } 999 | run_hook 'post-clean' 1000 | end 1001 | 1002 | def exec_distclean 1003 | rm_f ConfigTable.savefile 1004 | run_hook 'pre-distclean' 1005 | each_selected_installers {|inst| inst.exec_distclean } 1006 | run_hook 'post-distclean' 1007 | end 1008 | 1009 | # 1010 | # lib 1011 | # 1012 | 1013 | def each_selected_installers 1014 | Dir.mkdir 'packages' unless File.dir?('packages') 1015 | @selected.each do |pack| 1016 | $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose'] 1017 | Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") 1018 | Dir.chdir "packages/#{pack}" 1019 | yield @installers[pack] 1020 | Dir.chdir '../..' 1021 | end 1022 | end 1023 | 1024 | def verbose? 1025 | @options['verbose'] 1026 | end 1027 | 1028 | def no_harm? 1029 | @options['no-harm'] 1030 | end 1031 | 1032 | end 1033 | 1034 | 1035 | class Installer 1036 | 1037 | FILETYPES = %w( bin lib ext data ) 1038 | 1039 | include HookScriptAPI 1040 | include HookUtils 1041 | include FileOperations 1042 | 1043 | def initialize(config, opt, srcroot, objroot) 1044 | @config = config 1045 | @options = opt 1046 | @srcdir = File.expand_path(srcroot) 1047 | @objdir = File.expand_path(objroot) 1048 | @currdir = '.' 1049 | end 1050 | 1051 | def inspect 1052 | "#<#{self.class} #{File.basename(@srcdir)}>" 1053 | end 1054 | 1055 | # 1056 | # Hook Script API base methods 1057 | # 1058 | 1059 | def srcdir_root 1060 | @srcdir 1061 | end 1062 | 1063 | def objdir_root 1064 | @objdir 1065 | end 1066 | 1067 | def relpath 1068 | @currdir 1069 | end 1070 | 1071 | # 1072 | # configs/options 1073 | # 1074 | 1075 | def no_harm? 1076 | @options['no-harm'] 1077 | end 1078 | 1079 | def verbose? 1080 | @options['verbose'] 1081 | end 1082 | 1083 | def verbose_off 1084 | begin 1085 | save, @options['verbose'] = @options['verbose'], false 1086 | yield 1087 | ensure 1088 | @options['verbose'] = save 1089 | end 1090 | end 1091 | 1092 | # 1093 | # TASK config 1094 | # 1095 | 1096 | def exec_config 1097 | exec_task_traverse 'config' 1098 | end 1099 | 1100 | def config_dir_bin(rel) 1101 | end 1102 | 1103 | def config_dir_lib(rel) 1104 | end 1105 | 1106 | def config_dir_ext(rel) 1107 | extconf if extdir?(curr_srcdir()) 1108 | end 1109 | 1110 | def extconf 1111 | opt = @options['config-opt'].join(' ') 1112 | command "#{config('rubyprog')} \"#{curr_srcdir()}/extconf.rb\" #{opt}" 1113 | end 1114 | 1115 | def config_dir_data(rel) 1116 | end 1117 | 1118 | # 1119 | # TASK setup 1120 | # 1121 | 1122 | def exec_setup 1123 | exec_task_traverse 'setup' 1124 | end 1125 | 1126 | def setup_dir_bin(rel) 1127 | all_files_in(curr_srcdir()).each do |fname| 1128 | adjust_shebang "#{curr_srcdir()}/#{fname}" 1129 | end 1130 | end 1131 | 1132 | def adjust_shebang(path) 1133 | return if no_harm? 1134 | tmpfile = File.basename(path) + '.tmp' 1135 | begin 1136 | File.open(path, 'rb') {|r| 1137 | first = r.gets 1138 | return unless File.basename(config('rubypath')) == 'ruby' 1139 | return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby' 1140 | $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose? 1141 | File.open(tmpfile, 'wb') {|w| 1142 | w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath')) 1143 | w.write r.read 1144 | } 1145 | move_file tmpfile, File.basename(path) 1146 | } 1147 | ensure 1148 | File.unlink tmpfile if File.exist?(tmpfile) 1149 | end 1150 | end 1151 | 1152 | def setup_dir_lib(rel) 1153 | end 1154 | 1155 | def setup_dir_ext(rel) 1156 | make if extdir?(curr_srcdir()) 1157 | end 1158 | 1159 | def setup_dir_data(rel) 1160 | end 1161 | 1162 | # 1163 | # TASK install 1164 | # 1165 | 1166 | def exec_install 1167 | rm_f 'InstalledFiles' 1168 | exec_task_traverse 'install' 1169 | end 1170 | 1171 | def install_dir_bin(rel) 1172 | install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755 1173 | end 1174 | 1175 | def install_dir_lib(rel) 1176 | install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644 1177 | end 1178 | 1179 | def install_dir_ext(rel) 1180 | return unless extdir?(curr_srcdir()) 1181 | install_files ruby_extentions('.'), 1182 | "#{config('sodir')}/#{File.dirname(rel)}", 1183 | 0555 1184 | end 1185 | 1186 | def install_dir_data(rel) 1187 | install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644 1188 | end 1189 | 1190 | def install_files(list, dest, mode) 1191 | mkdir_p dest, @options['install-prefix'] 1192 | list.each do |fname| 1193 | install fname, dest, mode, @options['install-prefix'] 1194 | end 1195 | end 1196 | 1197 | def ruby_scripts 1198 | collect_filenames_auto().select {|n| /\.rb\z/ =~ n } 1199 | end 1200 | 1201 | # picked up many entries from cvs-1.11.1/src/ignore.c 1202 | reject_patterns = %w( 1203 | core RCSLOG tags TAGS .make.state 1204 | .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb 1205 | *~ *.old *.bak *.BAK *.orig *.rej _$* *$ 1206 | 1207 | *.org *.in .* 1208 | ) 1209 | mapping = { 1210 | '.' => '\.', 1211 | '$' => '\$', 1212 | '#' => '\#', 1213 | '*' => '.*' 1214 | } 1215 | REJECT_PATTERNS = Regexp.new('\A(?:' + 1216 | reject_patterns.map {|pat| 1217 | pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] } 1218 | }.join('|') + 1219 | ')\z') 1220 | 1221 | def collect_filenames_auto 1222 | mapdir((existfiles() - hookfiles()).reject {|fname| 1223 | REJECT_PATTERNS =~ fname 1224 | }) 1225 | end 1226 | 1227 | def existfiles 1228 | all_files_in(curr_srcdir()) | all_files_in('.') 1229 | end 1230 | 1231 | def hookfiles 1232 | %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| 1233 | %w( config setup install clean ).map {|t| sprintf(fmt, t) } 1234 | }.flatten 1235 | end 1236 | 1237 | def mapdir(filelist) 1238 | filelist.map {|fname| 1239 | if File.exist?(fname) # objdir 1240 | fname 1241 | else # srcdir 1242 | File.join(curr_srcdir(), fname) 1243 | end 1244 | } 1245 | end 1246 | 1247 | def ruby_extentions(dir) 1248 | Dir.open(dir) {|d| 1249 | ents = d.select {|fname| /\.#{::RbConfig::CONFIG['DLEXT']}\z/ =~ fname } 1250 | if ents.empty? 1251 | setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" 1252 | end 1253 | return ents 1254 | } 1255 | end 1256 | 1257 | # 1258 | # TASK clean 1259 | # 1260 | 1261 | def exec_clean 1262 | exec_task_traverse 'clean' 1263 | rm_f ConfigTable.savefile 1264 | rm_f 'InstalledFiles' 1265 | end 1266 | 1267 | def clean_dir_bin(rel) 1268 | end 1269 | 1270 | def clean_dir_lib(rel) 1271 | end 1272 | 1273 | def clean_dir_ext(rel) 1274 | return unless extdir?(curr_srcdir()) 1275 | make 'clean' if File.file?('Makefile') 1276 | end 1277 | 1278 | def clean_dir_data(rel) 1279 | end 1280 | 1281 | # 1282 | # TASK distclean 1283 | # 1284 | 1285 | def exec_distclean 1286 | exec_task_traverse 'distclean' 1287 | rm_f ConfigTable.savefile 1288 | rm_f 'InstalledFiles' 1289 | end 1290 | 1291 | def distclean_dir_bin(rel) 1292 | end 1293 | 1294 | def distclean_dir_lib(rel) 1295 | end 1296 | 1297 | def distclean_dir_ext(rel) 1298 | return unless extdir?(curr_srcdir()) 1299 | make 'distclean' if File.file?('Makefile') 1300 | end 1301 | 1302 | # 1303 | # lib 1304 | # 1305 | 1306 | def exec_task_traverse(task) 1307 | run_hook "pre-#{task}" 1308 | FILETYPES.each do |type| 1309 | if config('without-ext') == 'yes' and type == 'ext' 1310 | $stderr.puts 'skipping ext/* by user option' if verbose? 1311 | next 1312 | end 1313 | traverse task, type, "#{task}_dir_#{type}" 1314 | end 1315 | run_hook "post-#{task}" 1316 | end 1317 | 1318 | def traverse(task, rel, mid) 1319 | dive_into(rel) { 1320 | run_hook "pre-#{task}" 1321 | __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') 1322 | all_dirs_in(curr_srcdir()).each do |d| 1323 | traverse task, "#{rel}/#{d}", mid 1324 | end 1325 | run_hook "post-#{task}" 1326 | } 1327 | end 1328 | 1329 | def dive_into(rel) 1330 | return unless File.dir?("#{@srcdir}/#{rel}") 1331 | 1332 | dir = File.basename(rel) 1333 | Dir.mkdir dir unless File.dir?(dir) 1334 | prevdir = Dir.pwd 1335 | Dir.chdir dir 1336 | $stderr.puts '---> ' + rel if verbose? 1337 | @currdir = rel 1338 | yield 1339 | Dir.chdir prevdir 1340 | $stderr.puts '<--- ' + rel if verbose? 1341 | @currdir = File.dirname(rel) 1342 | end 1343 | 1344 | end 1345 | 1346 | 1347 | if $0 == __FILE__ 1348 | begin 1349 | if multipackage_install? 1350 | ToplevelInstallerMulti.invoke 1351 | else 1352 | ToplevelInstaller.invoke 1353 | end 1354 | rescue SetupError 1355 | raise if $DEBUG 1356 | $stderr.puts $!.message 1357 | $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." 1358 | exit 1 1359 | end 1360 | end 1361 | -------------------------------------------------------------------------------- /test/Base.java: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // this test class was taken from Mr. Micael Weller's bug report 3 | package jp.co.infoseek.hp.arton.rjb; 4 | 5 | public class Base { 6 | public String getInstanceVar() { 7 | return "hello"; 8 | } 9 | public static String getSVal() { 10 | return "sVal"; 11 | } 12 | public static String val() { 13 | return "val"; 14 | } 15 | public static String Val() { 16 | return "Val"; 17 | } 18 | public static String intf(Object x) { 19 | return x.toString(); 20 | } 21 | public static final int _NUMBER_FIVE = 5; 22 | public static void main(String[] args) { 23 | System.out.println(intf(IBase.class)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/CallbackTest.java: -------------------------------------------------------------------------------- 1 | package jp.co.infoseek.hp.arton.rjb; 2 | 3 | public class CallbackTest { 4 | public interface Callback { 5 | String method(long lval, short s, int n, double d, String str); 6 | } 7 | 8 | public static String callCallback(Callback cb) { 9 | return cb.method(1234L, (short)1234, 1234, 1234.5, "1234"); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test/ExtBase.java: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // this test class was taken from Mr. Micael Weller's bug report 3 | package jp.co.infoseek.hp.arton.rjb; 4 | 5 | public class ExtBase extends Base { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /test/IBase.java: -------------------------------------------------------------------------------- 1 | package jp.co.infoseek.hp.arton.rjb; 2 | 3 | public interface IBase { 4 | String getSVal(); 5 | } 6 | 7 | -------------------------------------------------------------------------------- /test/JTest.java: -------------------------------------------------------------------------------- 1 | import jp.co.infoseek.hp.arton.rjb.Test; 2 | 3 | public class JTest { 4 | static final String[] rs = new String[] { "a", "b", "c", "d", "e", 5 | "f", "g", "h", "i" }; 6 | static final Integer[] ri = new Integer[] { new Integer(1), 7 | new Integer(2), 8 | new Integer(3), 9 | new Integer(4), 10 | new Integer(5), 11 | new Integer(6), 12 | new Integer(7), 13 | new Integer(8), 14 | new Integer(9) 15 | }; 16 | public static void main(String[] args) { 17 | Test t = new Test(); 18 | String[] a = t.joinStringArray(new String[][] { 19 | {"a", "b", "c"}, {"d", "e", "f"}, {"g", "h", "i"} }); 20 | System.out.println(a.length); 21 | for (int i = 0; i < a.length; i++) { 22 | System.out.print(a[i]); 23 | if (rs[i] != a[i]) { 24 | System.out.println("bad result !"); 25 | System.exit(1); 26 | } 27 | } 28 | System.out.println(""); 29 | Integer[] ai = t.joinIntArray(new int[][] { 30 | { 1, 2, 3, }, { 4, 5, 6, }, { 7, 8, 9, } }); 31 | System.out.println(ai.length); 32 | for (int i = 0; i < ai.length; i++) { 33 | System.out.print(ai[i]); 34 | if (!ri[i].equals(ai[i])) { 35 | System.out.println("bad result !"); 36 | System.exit(1); 37 | } 38 | } 39 | System.out.println(""); 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /test/JarTest.java: -------------------------------------------------------------------------------- 1 | // $Id:$ 2 | package jp.co.infoseek.hp.arton.rjb; 3 | 4 | public class JarTest { 5 | public String add(String a, String b) { 6 | return a + b; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/JarTest2.java: -------------------------------------------------------------------------------- 1 | package jp.co.infoseek.hp.arton.rjb; 2 | 3 | public class JarTest2 extends JarTest { 4 | public String add(String a, String b) { 5 | return super.add(a, b) + " extended"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/Test.java: -------------------------------------------------------------------------------- 1 | // 2 | // $Id: Test.java 168 2011-07-15 18:57:04Z arton $ 3 | // 4 | package jp.co.infoseek.hp.arton.rjb; 5 | import java.net.URI; 6 | import java.util.ArrayList; 7 | import java.util.Iterator; 8 | import java.util.Comparator; 9 | import java.util.SortedMap; 10 | import java.util.TreeMap; 11 | import java.math.BigDecimal; 12 | 13 | public class Test { 14 | public String concat(Iterator i) { 15 | StringBuffer sb = new StringBuffer(); 16 | for (; i.hasNext(); ) { 17 | sb.append(i.next()); 18 | } 19 | return new String(sb); 20 | } 21 | public int check(Comparator c, int x, int y) { 22 | return c.compare(new Integer(x), new Integer(y)); 23 | } 24 | public String[][] getStringArrayOfArrays() { 25 | return new String[][] { { "abc", "def" }, { "123", "456" } }; 26 | } 27 | 28 | public int[][] getIntArrayOfArrays() { 29 | return new int[][] { { 1,2,3 }, { 4, 5, 6} }; 30 | } 31 | 32 | public Object[][][] getMixedArray() { 33 | return new Object[][][] { 34 | { 35 | {12, "test", new Integer(15), new BigDecimal("1234.567")}, {} 36 | }, 37 | { 38 | {"a string","another string"}, {1,2,3}, {4,5,6} 39 | }, 40 | { 41 | }, 42 | }; 43 | } 44 | 45 | public String[][][][] getSizedArray() { 46 | String[][][][] sizedArray = new String[1][2][3][4]; 47 | sizedArray[0][1][2][3]="find me"; 48 | return sizedArray; 49 | } 50 | 51 | public String[] joinStringArray(String[][] aa) { 52 | ArrayList list = new ArrayList(); 53 | for (int i = 0; i < aa.length; i++) { 54 | for (int j = 0; j < aa[i].length; j++) { 55 | list.add(aa[i][j]); 56 | } 57 | } 58 | return list.toArray(new String[list.size()]); 59 | } 60 | public Integer[] joinIntArray(int[][] aa) { 61 | ArrayList list = new ArrayList(); 62 | for (int i = 0; i < aa.length; i++) { 63 | for (int j = 0; j < aa[i].length; j++) { 64 | list.add(aa[i][j]); 65 | } 66 | } 67 | return list.toArray(new Integer[list.size()]); 68 | } 69 | public int[][][] throughIntArray(int[][][] a) { 70 | return a; 71 | } 72 | public Object getObjectArray() { 73 | return new Object[] { 74 | new Integer(1), "Hello World !", 75 | }; 76 | } 77 | public Object getObjectArrayOfArray() { 78 | return new Object[][] { 79 | { new Integer(1), "Hello World !", }, 80 | { new Integer(2), "Hello World !!", }, 81 | }; 82 | } 83 | public void callWithArrays(byte[] ab, short[] as, int[] ai, 84 | long[] al, double[] ad, float[] af, 85 | String[] ax, Object[] ao) 86 | { 87 | } 88 | public enum TestTypes { 89 | ONE, TWO, THREE 90 | } 91 | 92 | public SortedMap getSortedMap() { 93 | SortedMap map = new TreeMap(); 94 | map.put("abc", new byte[]{0,1,2,3,4}); 95 | map.put("def", new byte[]{5,6,7,8,9}); 96 | return map; 97 | } 98 | 99 | public static SortedMap getSortedMapS() { 100 | SortedMap map = new TreeMap(); 101 | map.put("abc", new byte[]{0,1,2,3,4}); 102 | map.put("def", new byte[]{5,6,7,8,9}); 103 | return map; 104 | } 105 | 106 | public SortedMap throughSortedMap(SortedMap map) { 107 | SortedMap value = map; 108 | return value; 109 | } 110 | 111 | public static void setSortedMapS(SortedMap map) { 112 | SortedMap value = map; 113 | } 114 | 115 | public boolean isSameString(String s) { 116 | return "漢字テキスト".equals(s); 117 | } 118 | 119 | public String getUmlaut() { 120 | return "\u01D6" + "\u00FC\u0304" + "\u0075\u0308\u0304" + "\ud869\udeb2" + "\u304b\u309a"; 121 | } 122 | 123 | public String[] getJavaTypedArray(String[] o, Integer[] n, URI[] u) { 124 | return new String[] { o.getClass().getName(), 125 | n.getClass().getName(), 126 | u.getClass().getName() }; 127 | } 128 | 129 | public void causeException() { 130 | try { 131 | throw new IllegalArgumentException("bad argument"); 132 | } catch (Exception e) { 133 | throw new IllegalStateException("outer exception", e); 134 | } 135 | } 136 | 137 | public String helloData = "Hello World !!"; 138 | 139 | public static void main(String[] args) { 140 | Test test = new Test(); 141 | System.out.println(test.getUmlaut()); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /test/Test105.java: -------------------------------------------------------------------------------- 1 | package jp.co.infoseek.hp.arton.rjb; 2 | public class Test105 { 3 | public String test; 4 | public Test105(String test) { 5 | this.test = test; 6 | } 7 | public String test() { 8 | return "method_" + test; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/Two.java: -------------------------------------------------------------------------------- 1 | package jp.co.infoseek.hp.arton.rjb; 2 | public interface Two { 3 | public String method1(); 4 | public String method2(); 5 | 6 | } 7 | -------------------------------------------------------------------------------- /test/TwoCaller.java: -------------------------------------------------------------------------------- 1 | package jp.co.infoseek.hp.arton.rjb; 2 | public class TwoCaller { 3 | public String[] foo(Two t) { 4 | String[] ret = new String[2]; 5 | ret[0] = t.method1(); 6 | ret[1] = t.method2(); 7 | return ret; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/anon-test-60.rb: -------------------------------------------------------------------------------- 1 | require 'rjb' 2 | Rjb::load 3 | begin 4 | Rjb::import('java.lang.Integer').parseInt('x') 5 | rescue => e 6 | begin 7 | raise e 8 | rescue => f 9 | if e.class == f.class 10 | puts "I expect the equality to be true" 11 | else 12 | puts "Unexpectedly the re-raised Java exception has changed " + 13 | "from a #{e.class} into a #{f.class}" 14 | end 15 | end 16 | end 17 | 18 | -------------------------------------------------------------------------------- /test/exttest.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | # $Id:$ 4 | 5 | begin 6 | require 'rjb' 7 | rescue LoadError 8 | require 'rubygems' 9 | require 'rjb' 10 | end 11 | 12 | if Rjb::VERSION < '1.2.2' 13 | puts "Rjb #{Rjb::VERSION} does not support rjbextension. exit" 14 | exit 0 15 | end 16 | 17 | require 'rjbextension' 18 | require 'test/unit' 19 | require 'fileutils' 20 | 21 | FileUtils.rm_f 'jp/co/infoseek/hp/arton/rjb/Base.class' 22 | 23 | puts "start RJB(#{Rjb::VERSION}) test" 24 | class ExtTestRjb < Test::Unit::TestCase 25 | 26 | def jp 27 | JavaPackage.new('jp') 28 | end 29 | 30 | def test_absolute_path_require 31 | assert !Rjb::loaded? 32 | require File.absolute_path('./rjbtest.jar') 33 | Rjb::load 34 | assert Rjb::loaded? 35 | base = jp.co.infoseek.hp.arton.rjb.Base.new 36 | assert_equal('hello', base.instance_var) 37 | end 38 | 39 | def test_require_extension 40 | org_load_path = $LOAD_PATH 41 | $LOAD_PATH << '.' 42 | require 'rjbtest.jar' 43 | Rjb::load 44 | assert Rjb::loaded? 45 | base = jp.co.infoseek.hp.arton.rjb.Base.new 46 | assert_equal('hello', base.instance_var) 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /test/gctest.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'rjb' 3 | 4 | class TestRjbGC < Test::Unit::TestCase 5 | include Rjb 6 | def setup 7 | load(nil, ['-verbose:gc']) 8 | end 9 | 10 | def tearDown 11 | unload 12 | end 13 | 14 | def test_gc 15 | stringBuffer = import('java.lang.StringBuffer') 16 | (0..1000).each do |i| 17 | sb = stringBuffer.new 18 | (0..1000).each do |j| 19 | sb.append(' ') 20 | end 21 | GC.start 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/jartest.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jartest.jar -------------------------------------------------------------------------------- /test/jartest.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | 4 | begin 5 | require 'rjb' 6 | rescue LoadError 7 | require 'rubygems' 8 | require 'rjb' 9 | end 10 | require 'test/unit' 11 | 12 | class JarTest < Test::Unit::TestCase 13 | include Rjb 14 | 15 | def setup 16 | Rjb::load() 17 | end 18 | 19 | def test_depends 20 | add_jar(File.expand_path('./jartest2.jar')) 21 | add_jar(File.expand_path('./jartest.jar')) 22 | assert Rjb::import('jp.co.infoseek.hp.arton.rjb.JarTest2') 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/jartest2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jartest2.jar -------------------------------------------------------------------------------- /test/jartest2.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | 4 | begin 5 | require 'rjb' 6 | rescue LoadError 7 | require 'rubygems' 8 | require 'rjb' 9 | end 10 | require 'test/unit' 11 | 12 | class JarTest < Test::Unit::TestCase 13 | include Rjb 14 | 15 | def setup 16 | Rjb::load() 17 | end 18 | 19 | def test_depends 20 | add_jar([File.expand_path('./jartest2.jar'), File.expand_path('./jartest.jar')]) 21 | assert Rjb::import('jp.co.infoseek.hp.arton.rjb.JarTest2') 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /test/jartest3.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | 4 | begin 5 | require 'rjb' 6 | rescue LoadError 7 | require 'rubygems' 8 | require 'rjb' 9 | end 10 | require 'test/unit' 11 | 12 | class JarTest < Test::Unit::TestCase 13 | include Rjb 14 | 15 | def setup 16 | Rjb::load() 17 | end 18 | 19 | def test_depends 20 | add_jar(File.expand_path('./jartest2.jar')) 21 | begin 22 | Rjb::import('jp.co.infoseek.hp.arton.rjb.JarTest2') 23 | fail 'no exception' 24 | rescue => e 25 | ['NoClassDefFoundError', 'ClassNotFoundException'].any? {|nm| e.class == nm} 26 | assert true 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/CallbackTest$Callback.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/CallbackTest$Callback.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/CallbackTest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/CallbackTest.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/IBase.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/IBase.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/JarTest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/JarTest.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/JarTest2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/JarTest2.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/Test$TestTypes.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/Test$TestTypes.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/Test.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/Test.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/Two.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/Two.class -------------------------------------------------------------------------------- /test/jp/co/infoseek/hp/arton/rjb/TwoCaller.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/jp/co/infoseek/hp/arton/rjb/TwoCaller.class -------------------------------------------------------------------------------- /test/listtest.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | =begin 4 | Copyright(c) 2012 arton 5 | =end 6 | 7 | begin 8 | require 'rjb/list' 9 | rescue LoadError 10 | require 'rubygems' 11 | require 'rjb/list' 12 | end 13 | require 'test/unit' 14 | require 'fileutils' 15 | 16 | class ListTest < Test::Unit::TestCase 17 | include Rjb 18 | def test_create 19 | ja = import('java.util.ArrayList') 20 | a = ja.new 21 | a.add(1) 22 | a.add(2) 23 | a.add(3) 24 | n = 1 25 | a.each do |x| 26 | assert_equal n, x.intValue 27 | n += 1 28 | end 29 | assert_equal 4, n 30 | end 31 | def test_returned_proxy 32 | ja = import('java.util.Arrays') 33 | a = ja.as_list([1, 2, 3]) 34 | n = 1 35 | a.each do |x| 36 | assert_equal n, x.intValue 37 | n += 1 38 | end 39 | assert_equal 4, n 40 | end 41 | def test_iterator 42 | ja = import('java.util.Arrays') 43 | it = ja.as_list([1, 2, 3]).iterator 44 | n = 1 45 | it.each do |x| 46 | assert_equal n, x.intValue 47 | n += 1 48 | end 49 | assert_equal 4, n 50 | end 51 | def test_enumerable 52 | ja = import('java.util.Arrays') 53 | assert_equal 55, ja.as_list((1..10).to_a).inject(0) {|r, e| r + e.intValue} 54 | end 55 | end 56 | 57 | -------------------------------------------------------------------------------- /test/osx_jvmcheck.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | begin 3 | require 'rjb' 4 | rescue LoadError 5 | require 'rubygems' 6 | require 'rjb' 7 | end 8 | S = Rjb::import('java.lang.System') 9 | puts "#{S.property('java.vendor')} #{S.property('java.version')}" 10 | -------------------------------------------------------------------------------- /test/readme.txt: -------------------------------------------------------------------------------- 1 | how to run the test 2 | 3 | you should set lD_LIBRARY_PATH environment variable to point the JVM. 4 | 5 | for example) 6 | 7 | If you use Linux Sun Java2 Standard Edition, 8 | 9 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386:$JAVA_HOME/jre/lib/i386/client 10 | ruby test.rb 11 | 12 | -------------------------------------------------------------------------------- /test/rjbtest.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arton/rjb/c84a4ea1f3f6756cabdc9f1193f9c9ee15cefa4f/test/rjbtest.jar -------------------------------------------------------------------------------- /test/test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | # $Id: test.rb 199 2012-12-17 13:31:18Z arton $ 4 | 5 | begin 6 | require 'rjb' 7 | rescue LoadError 8 | require 'rubygems' 9 | require 'rjb' 10 | end 11 | require 'test/unit' 12 | require 'fileutils' 13 | 14 | FileUtils.rm_f 'jp/co/infoseek/hp/arton/rjb/Base.class' 15 | FileUtils.rm_f 'jp/co/infoseek/hp/arton/rjb/ExtBase.class' 16 | 17 | puts "start RJB(#{Rjb::VERSION}) test" 18 | class TestRjb < Test::Unit::TestCase 19 | include Rjb 20 | def setup 21 | Rjb::load('.') 22 | Rjb::add_jar(File.expand_path('rjbtest.jar')) 23 | Rjb::primitive_conversion = false 24 | 25 | @jString = import('java.lang.String') 26 | @jInteger = import('java.lang.Integer') 27 | @jShort = import('java.lang.Short') 28 | @jDouble = import('java.lang.Double') 29 | @jFloat = import('java.lang.Float') 30 | @jBoolean = import('java.lang.Boolean') 31 | @jByte = import('java.lang.Byte') 32 | @jLong = import('java.lang.Long') 33 | @jChar = import('java.lang.Character') 34 | end 35 | 36 | def teardown 37 | end 38 | 39 | def test_metaclass 40 | cls = import('java.lang.Class') 41 | assert_equal('java.lang.Class', cls._classname) 42 | assert_equal('java.lang.Class', cls.getName) 43 | assert_equal(17, cls.getModifiers) 44 | end 45 | 46 | def test_scalar 47 | assert_equal('java.lang.Class', @jString._classname) 48 | assert_equal('class java.lang.String', @jString.toString) 49 | str = @jString.new 50 | assert_equal('java.lang.String', str._classname) 51 | assert_equal(0, str.length) 52 | assert_equal('', str.toString) 53 | str = @jString.new_with_sig('Ljava.lang.String;', "abcde") 54 | # result integer 55 | assert_equal(5, str.length) 56 | # result string 57 | assert_equal('abcde', str.toString) 58 | # argument test 59 | # char 60 | assert_equal('abxde', str.replace("c".sum, "x".sum)) 61 | # string 62 | assert_equal('abdxe', str.replaceAll('cd', 'dx')) 63 | # int 64 | assert_equal('bc', str.substring(1, 3)) 65 | assert_equal('e', str.substring(4)) 66 | # float with static 67 | assert_equal('5.23', @jString._invoke('valueOf', 'F', 5.23)) 68 | assert_equal('25.233', @jString._invoke('valueOf', 'D', 25.233)) 69 | # rjb object (String) 70 | str2 = @jString.new_with_sig('Ljava.lang.String;', 'fghijk') 71 | assert_equal('abcdefghijk', str.concat(str2)) 72 | # rjb object other (implicit toString call is Rjb feature) 73 | i = @jInteger.new_with_sig('I', 35901) 74 | assert_equal('abcde35901', str.concat(i)) 75 | # result boolean and argument is rjb object 76 | assert_equal(false, i.equals(str)) 77 | assert_equal(false, str.equals(i)) 78 | assert_equal(true, str.equals("abcde")) 79 | assert_equal(true, str.equals(str)) 80 | # long 81 | l = @jLong.new_with_sig('J', -9223372036854775808) 82 | assert_equal(-9223372036854775808, l.longValue) 83 | l = @jLong.new_with_sig('J', 9223372036854775807) 84 | assert_equal(9223372036854775807, l.longValue) 85 | # double 86 | d = @jDouble.new_with_sig('D', 1234.5678901234567890) 87 | assert_equal(1234.5678901234567890, d.doubleValue) 88 | # byte 89 | b = @jByte.new_with_sig('B', 13) 90 | assert_equal(13, b.byteValue) 91 | # float 92 | f = @jFloat.new_with_sig('F', 13.5) 93 | assert_equal(13.5, f.floatValue) 94 | # short 95 | s = @jShort.new_with_sig('S', 1532) 96 | assert_equal(1532, s.shortValue) 97 | c = @jChar.new_with_sig('C', "A".sum) 98 | assert_equal("A".sum, c.charValue) 99 | end 100 | 101 | def test_array 102 | str = @jString.new_with_sig('[C', ["a".sum, "b".sum, "c".sum, "d".sum, "e".sum, "c".sum, "f".sum, "c".sum, "g".sum]) 103 | assert_equal('abcdecfcg', str.toString) 104 | # conv string array 105 | splt = str.split('c') 106 | assert(Array === splt) 107 | assert_equal(4, splt.size) 108 | assert_equal('ab', splt[0]) 109 | assert_equal('g', splt[3]) 110 | # conv byte array to (ruby)string 111 | ba = str.getBytes 112 | assert_equal('abcdecfcg', ba) 113 | # conv char array to array(int) 114 | ca = str.toCharArray 115 | assert_equal(["a".sum, "b".sum, "c".sum, "d".sum, "e".sum, "c".sum, "f".sum, "c".sum, "g".sum], ca) 116 | end 117 | 118 | def test_importobj() 119 | sys = import('java.lang.System') 120 | props = sys.getProperties 121 | assert_equal('java.util.Properties', props._classname) 122 | if /cygwin/ =~ RUBY_PLATFORM # patch for dirty environment 123 | assert_equal(Dir::pwd, %x[cygpath -u #{props.getProperty('user.dir').gsub('\\', '/')}].chop) 124 | else 125 | assert_equal(Dir::pwd, props.getProperty('user.dir').gsub('\\', '/')) 126 | end 127 | assert_equal(@jBoolean.valueOf(true).booleanValue(), true) 128 | assert_equal(@jBoolean.valueOf(false).booleanValue(), false) 129 | assert_equal(@jBoolean.valueOf('true').booleanValue(), true) 130 | assert_equal(@jBoolean.valueOf('false').booleanValue(), false) 131 | end 132 | 133 | def test_importobjarray() 134 | jarray = import('java.util.ArrayList') 135 | a = jarray.new() 136 | a.add(@jInteger.new_with_sig('I', 1)) 137 | a.add(@jInteger.new_with_sig('I', 2)) 138 | a.add(@jInteger.new_with_sig('I', 3)) 139 | oa = a.toArray 140 | assert_equal(3, oa.size) 141 | assert_equal(1, oa[0].intValue) 142 | assert_equal(2, oa[1].intValue) 143 | assert_equal(3, oa[2].intValue) 144 | end 145 | 146 | def test_kjconv() 147 | if Object::const_defined?(:Encoding) 148 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 149 | euc_kj = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8".force_encoding Encoding::EUC_JP 150 | s = @jString.new_with_sig('Ljava.lang.String;', euc_kj) 151 | assert_equal(s.toString().encoding, Encoding::UTF_8) 152 | assert(test.isSameString(s)) 153 | assert(test.isSameString(euc_kj)) 154 | assert_equal(s.toString().encode(Encoding::EUC_JP), euc_kj) 155 | sjis_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67".force_encoding Encoding::SHIFT_JIS 156 | s = @jString.new_with_sig('Ljava.lang.String;', sjis_kj) 157 | assert_equal(s.toString().encoding, Encoding::UTF_8) 158 | assert(test.isSameString(s)) 159 | assert(test.isSameString(sjis_kj)) 160 | assert_equal(s.toString().encode(Encoding::SHIFT_JIS), sjis_kj) 161 | utf8_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88".force_encoding Encoding::UTF_8 162 | s = @jString.new_with_sig('Ljava.lang.String;', utf8_kj) 163 | assert_equal(s.toString().encoding, Encoding::UTF_8) 164 | assert(test.isSameString(s)) 165 | assert(test.isSameString(utf8_kj)) 166 | assert_equal(s.toString().encode(Encoding::UTF_8), utf8_kj) 167 | iso2022jp_kj = "\x1b\x24\x42\x34\x41\x3b\x7a\x25\x46\x25\x2d\x25\x39\x25\x48\x1b\x28\x42".force_encoding Encoding::ISO_2022_JP 168 | s = @jString.new_with_sig('Ljava.lang.String;', iso2022jp_kj) 169 | assert_equal(s.toString().encoding, Encoding::UTF_8) 170 | assert(test.isSameString(s)) 171 | assert(test.isSameString(iso2022jp_kj)) 172 | assert_equal(s.toString().encode(Encoding::ISO_2022_JP), iso2022jp_kj) 173 | assert_equal(@jString.new("abcdef".force_encoding(Encoding::ASCII_8BIT)).toString(), "abcdef") 174 | assert_equal(@jString.new("abcdef".force_encoding(Encoding::find("us-ascii"))).toString(), "abcdef") 175 | else 176 | default_kcode = $KCODE 177 | begin 178 | $KCODE = 'euc' 179 | euc_kj = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8" 180 | s = @jString.new(euc_kj) 181 | assert_equal(s.toString(), euc_kj) 182 | $KCODE = 'sjis' 183 | sjis_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" 184 | s = @jString.new(sjis_kj) 185 | assert_equal(s.toString(), sjis_kj) 186 | $KCODE = 'utf8' 187 | utf8_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" 188 | s = @jString.new(utf8_kj) 189 | assert_equal(s.toString(), utf8_kj) 190 | $KCODE = 'none' 191 | if /mswin(?!ce)|mingw|cygwin|bccwin/ =~ RUBY_PLATFORM 192 | #expecting shift_jis on windows 193 | none_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" 194 | else 195 | #expecting utf-8 unless windows 196 | none_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" 197 | end 198 | s = @jString.new(none_kj) 199 | assert_equal(s.toString(), none_kj) 200 | $KCODE = 'utf8' 201 | utf8_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" 202 | s = @jString.new(utf8_kj) 203 | assert_equal(s.toString(), utf8_kj) 204 | $KCODE = 'sjis' 205 | sjis_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" 206 | s = @jString.new(sjis_kj) 207 | assert_equal(s.toString(), sjis_kj) 208 | $KCODE = 'euc' 209 | euc_kj = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8" 210 | s = @jString.new(euc_kj) 211 | assert_equal(s.toString(), euc_kj) 212 | ensure 213 | $KCODE = default_kcode 214 | end 215 | end 216 | end 217 | 218 | def test_combination_charcters 219 | teststr = "\xc7\x96\xc3\xbc\xcc\x84\x75\xcc\x88\xcc\x84𪚲\xe3\x81\x8b\xe3\x82\x9a" 220 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 221 | s = test.getUmlaut() 222 | if Object::const_defined?(:Encoding) #>=1.9 223 | =begin 224 | n = [teststr.bytes.length, s.bytes.length].max 225 | puts "org:#{teststr.bytes.length}, ret:#{s.bytes.length}" 226 | 0.upto(n - 1) do |i| 227 | b0 = teststr.getbyte(i) 228 | b0 = 0 unless b0 229 | b1 = s.getbyte(i) 230 | b1 = 0 unless b1 231 | puts sprintf("%02X - %02X\n", b0, b1) 232 | end 233 | =end 234 | assert_equal(teststr.bytes.length, s.bytes.length) 235 | assert_equal(teststr, s) 236 | else 237 | default_kcode = $KCODE 238 | begin 239 | $KCODE = "utf8" 240 | assert_equal(teststr, s) 241 | ensure 242 | $KCODE = default_kcode 243 | end 244 | end 245 | end 246 | 247 | def test_constants() 248 | assert_equal(0x7fffffffffffffff, @jLong.MAX_VALUE) 249 | assert_equal(-9223372036854775808, @jLong.MIN_VALUE) 250 | end 251 | 252 | class TestIter 253 | def initialize() 254 | @i = 5 255 | end 256 | def hasNext() 257 | @i > 0 258 | end 259 | def next() 260 | @i -= 1 261 | @i.to_s 262 | end 263 | end 264 | 265 | def test_newobject() 266 | it = TestIter.new 267 | it = bind(it, 'java.util.Iterator') 268 | test = import('jp.co.infoseek.hp.arton.rjb.Test') 269 | a = test.new 270 | assert_equal("43210", a.concat(it)) 271 | end 272 | 273 | def test_unbind() 274 | it = TestIter.new 275 | it = bind(it, 'java.util.Iterator') 276 | assert_equal(it, unbind(it)) 277 | end 278 | 279 | class TestComparator 280 | def compare(o1, o2) 281 | o1.to_i - o2.to_i 282 | end 283 | def equals(o) 284 | o == self 285 | end 286 | end 287 | 288 | def test_comparator 289 | cp = TestComparator.new 290 | cp = bind(cp, 'java.util.Comparator') 291 | test = import('jp.co.infoseek.hp.arton.rjb.Test') 292 | a = test.new 293 | assert_equal(0, a.check(cp, 123, 123)) 294 | assert_equal(5, a.check(cp, 81, 76)) 295 | assert_equal(-5, a.check(cp, 76, 81)) 296 | end 297 | 298 | # assert_raise is useless in this test, because NumberFormatException may be defined in 299 | # its block. 300 | def test_exception() 301 | begin 302 | @jInteger.parseInt('blabla') 303 | flunk('no exception') 304 | rescue NumberFormatException => e 305 | assert_nil(e.cause) 306 | # OK 307 | end 308 | end 309 | 310 | class TestIterator 311 | def initialize(tp) 312 | @type = tp 313 | end 314 | def hasNext() 315 | true 316 | end 317 | def next() 318 | if @type == 0 319 | Rjb::throw('java.util.NoSuchElementException', 'test exception') 320 | elsif @type == 1 321 | Rjb::throw(Rjb::import('java.util.NoSuchElementException').new('instance test')) 322 | end 323 | end 324 | end 325 | 326 | def test_throw() 327 | it = TestIterator.new(0) 328 | it = bind(it, 'java.util.Iterator') 329 | test = import('jp.co.infoseek.hp.arton.rjb.Test') 330 | a = test.new 331 | begin 332 | a.concat(it) 333 | flunk('no exception') 334 | rescue NoSuchElementException => e 335 | assert_equal('test exception', e.message) 336 | end 337 | end 338 | 339 | def test_instance_throw() 340 | it = TestIterator.new(1) 341 | it = bind(it, 'java.util.Iterator') 342 | test = import('jp.co.infoseek.hp.arton.rjb.Test') 343 | a = test.new 344 | begin 345 | a.concat(it) 346 | flunk('no exception') 347 | rescue NoSuchElementException => e 348 | assert_equal('instance test', e.message) 349 | end 350 | end 351 | 352 | def test_null_string() 353 | sys = import('java.lang.System') 354 | begin 355 | sys.getProperty(nil) 356 | flunk('no exception') 357 | rescue NullPointerException => e 358 | assert(true) 359 | rescue RuntimeError => e 360 | flunk(e.message) 361 | end 362 | end 363 | 364 | def test_throw_error() 365 | begin 366 | throw(self) 367 | flunk('no exception') 368 | rescue TypeError => e 369 | end 370 | begin 371 | throw(@jString.new('a')) 372 | flunk('no exception') 373 | rescue RuntimeError => e 374 | assert_equal('arg1 must be a throwable', e.message) 375 | end 376 | begin 377 | throw('java.lang.NoSuchException', 'test') 378 | flunk('no excpetion') 379 | rescue RuntimeError => e 380 | assert_equal("`java.lang.NoSuchException' not found", e.message) 381 | end 382 | end 383 | 384 | def test_throw_clear() 385 | assert_nothing_raised { 386 | begin 387 | Rjb::throw('java.util.NoSuchElementException', 'test exception') 388 | rescue #drop ruby exception 389 | end 390 | test = import('jp.co.infoseek.hp.arton.rjb.Test') 391 | begin 392 | Rjb::throw('java.util.NoSuchElementException', 'test exception') 393 | rescue #drop ruby exception 394 | end 395 | test.new 396 | begin 397 | Rjb::throw('java.util.NoSuchElementException', 'test exception') 398 | rescue #drop ruby exception 399 | end 400 | @jString.new_with_sig('Ljava.lang.String;', "abcde") 401 | begin 402 | Rjb::throw('java.util.NoSuchElementException', 'test exception') 403 | rescue #drop ruby exception 404 | end 405 | it = TestIterator.new(0) 406 | it = bind(it, 'java.util.Iterator') 407 | begin 408 | Rjb::throw('java.util.NoSuchElementException', 'test exception') 409 | rescue NoSuchElementException 410 | end 411 | begin 412 | Rjb::throw('java.lang.IllegalAccessException', 'test exception') 413 | rescue IllegalAccessException 414 | end 415 | unbind(it) 416 | } 417 | end 418 | 419 | def test_field() 420 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 421 | assert_equal('Hello World !!', test.helloData) 422 | test.helloData = 'Goodby World !' 423 | assert_equal('Goodby World !', test.helloData) 424 | end 425 | 426 | def test_instancemethod_from_class() 427 | begin 428 | assert_equal('true', @jString.valueOf(true)) 429 | @jString.length 430 | flunk('no exception') 431 | rescue RuntimeError => e 432 | assert_equal('instance method `length\' for class', e.message) 433 | end 434 | end 435 | 436 | def test_instancefield_from_class() 437 | point = import('java.awt.Point') 438 | begin 439 | point.x 440 | flunk('no exception') 441 | rescue RuntimeError => e 442 | assert_equal('instance field `x\' for class', e.message) 443 | end 444 | begin 445 | point.x = 30 446 | rescue RuntimeError => e 447 | assert_equal('instance field `x\' for class', e.message) 448 | end 449 | end 450 | 451 | def test_static_derived_method() 452 | ext = import('jp.co.infoseek.hp.arton.rjb.ExtBase') 453 | assert_equal("sVal", ext.getSVal) 454 | end 455 | 456 | def test_capitalized_method() 457 | bs = import('jp.co.infoseek.hp.arton.rjb.Base') 458 | assert_equal("val", bs.val) 459 | assert_equal("Val", bs.Val) 460 | end 461 | 462 | def test_underscored_constant() 463 | bs = import('jp.co.infoseek.hp.arton.rjb.Base') 464 | assert_equal(5, bs._NUMBER_FIVE) 465 | end 466 | 467 | def test_passingclass() 468 | ibs = import('jp.co.infoseek.hp.arton.rjb.IBase') 469 | bs = import('jp.co.infoseek.hp.arton.rjb.Base') 470 | assert_equal('interface jp.co.infoseek.hp.arton.rjb.IBase', bs.intf(ibs)) 471 | end 472 | 473 | def test_fornamehook() 474 | # j2se class 475 | cls = import('java.lang.Class') 476 | c = cls.forName('java.lang.Class') 477 | assert_equal(cls, c) 478 | # user class 479 | bs = import('jp.co.infoseek.hp.arton.rjb.Base') 480 | b = cls.forName('jp.co.infoseek.hp.arton.rjb.Base') 481 | assert_equal(bs, b) 482 | # check class that was loaded from classpath 483 | loader = Rjb::import('java.lang.ClassLoader') 484 | b = cls.forName('jp.co.infoseek.hp.arton.rjb.IBase', true, loader.getSystemClassLoader) 485 | assert(b.isInterface) 486 | end 487 | 488 | def test_send_array_of_arrays() 489 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 490 | a = test.joinStringArray([['ab', 'cd'], ['ef', 'gh']]) 491 | assert_equal(['ab', 'cd', 'ef', 'gh'], a) 492 | a = test.joinIntArray([[1, 2, 3], [4, 5, 6]]) 493 | a.collect! {|e| e.intValue } 494 | assert_equal([1, 2, 3, 4, 5, 6], a) 495 | r = [[[ 1, 2], [2, 3] ], [[ 3, 4], [5, 6]], [[7, 8], [1, 3]]] 496 | a = test.throughIntArray(r) 497 | assert_equal(a, r) 498 | end 499 | 500 | def test_import_and_instanciate() 501 | b = import('jp.co.infoseek.hp.arton.rjb.Base') 502 | assert_equal('hello', b.new.getInstanceVar()) 503 | end 504 | 505 | def test_array_of_arrays() 506 | jversion = import('java.lang.System').getProperty('java.version') 507 | if /^1\.5/ =~ jversion 508 | method = import('java.lang.reflect.Method') 509 | end 510 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 511 | a = test.getStringArrayOfArrays() 512 | assert_equal("abc", a[0][0]) 513 | assert_equal("def", a[0][1]) 514 | assert_equal("123", a[1][0]) 515 | assert_equal("456", a[1][1]) 516 | 517 | ints = test.getIntArrayOfArrays() 518 | assert_equal(2, ints.size ) 519 | assert_equal([1,2,3], ints[0] ) 520 | assert_equal([[1,2,3],[4,5,6]], ints ) 521 | 522 | sized = test.getSizedArray() 523 | assert_equal("find me",sized[0][1][2][3]) 524 | 525 | mixed = test.getMixedArray() 526 | assert_equal(12,mixed[0][0][0].intValue) 527 | assert_equal("another string",mixed[1][0][1].toString) 528 | assert_equal([],mixed[2]) 529 | end 530 | 531 | def test_CastObjectArray() 532 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 533 | a = test.getObjectArray() 534 | assert_equal(1, a[0].intValue) 535 | assert_equal('Hello World !', a[1].toString) 536 | a = test.getObjectArrayOfArray() 537 | assert_equal(1, a[0][0].intValue) 538 | assert_equal('Hello World !', a[0][1].toString) 539 | assert_equal(2, a[1][0].intValue) 540 | assert_equal('Hello World !!', a[1][1].toString) 541 | end 542 | 543 | def test_CallByNullForArrays() 544 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 545 | assert_equal(nil, test.callWithArrays(nil, nil, nil, nil, nil, nil, 546 | nil, nil)) 547 | end 548 | 549 | def test_failed_constructor_call() 550 | begin 551 | s = @jString.new('a', 'b', 'c') 552 | flunk('no exception') 553 | rescue RuntimeError => e 554 | assert(e) 555 | end 556 | end 557 | 558 | def test_rubyize 559 | loader = Rjb::import('java.lang.ClassLoader') 560 | cls = import('java.lang.Class') 561 | b = cls.for_name('jp.co.infoseek.hp.arton.rjb.IBase', true, loader.system_class_loader) 562 | assert(b.interface?) 563 | stringbuffer = Rjb::import('java.lang.StringBuffer') 564 | sb = stringbuffer.new('abc') 565 | assert_equal(1, sb.index_of('bc')) 566 | sb.set_char_at(1, "B".sum) 567 | assert_equal('aBc', sb.to_string) 568 | sb.length = 2 569 | assert_equal('aB', sb.to_string) 570 | end 571 | 572 | def test_auto_conv 573 | assert_equal(false, Rjb::primitive_conversion) 574 | Rjb::primitive_conversion = true 575 | assert_equal(true, Rjb::primitive_conversion) 576 | assert_equal(1, @jInteger.valueOf('1')) 577 | assert_equal(-1, @jInteger.valueOf('-1')) 578 | assert_equal(2, @jShort.valueOf('2')) 579 | assert_equal(-2, @jShort.valueOf('-2')) 580 | assert_equal(3.1, @jDouble.valueOf('3.1')) 581 | assert_equal(4.5, @jFloat.valueOf('4.5')) 582 | assert(@jBoolean.TRUE) 583 | assert_equal(5, @jByte.valueOf('5')) 584 | assert_equal(-6, @jByte.valueOf('-6')) 585 | assert_equal(0x7000000000000000, @jLong.valueOf('8070450532247928832')) 586 | assert_equal(-9223372036854775807, @jLong.valueOf('-9223372036854775807')) 587 | assert_equal("A".sum, @jChar.valueOf("A".sum)) 588 | end 589 | 590 | def test_obj_to_primitive 591 | ar = Rjb::import('java.util.ArrayList') 592 | a = ar.new 593 | a.add @jString.new('abcdef') 594 | a.add @jInteger.valueOf('1') 595 | a.add @jShort.valueOf('2') 596 | a.add @jDouble.valueOf('3.1') 597 | a.add @jFloat.valueOf('4.5') 598 | a.add @jBoolean.TRUE 599 | a.add @jByte.valueOf('5') 600 | a.add @jLong.valueOf('8070450532247928832') 601 | a.add @jChar.valueOf("A".sum) 602 | 603 | Rjb::primitive_conversion = true 604 | 605 | assert_equal 'abcdef', a.get(0) 606 | assert_equal 1, a.get(1) 607 | assert_equal 2, a.get(2) 608 | assert_equal 3.1, a.get(3) 609 | assert_equal 4.5, a.get(4) 610 | assert a.get(5) 611 | assert_equal 5, a.get(6) 612 | assert_equal 8070450532247928832, a.get(7) 613 | assert_equal "A".sum, a.get(8) 614 | end 615 | 616 | def test_primitive_to_obj 617 | Rjb::primitive_conversion = true 618 | 619 | ar = Rjb::import('java.util.ArrayList') 620 | a = ar.new 621 | a.add @jString.new('abcdef') 622 | a.add @jInteger.valueOf('1') 623 | a.add @jShort.valueOf('2') 624 | a.add @jDouble.valueOf('3.1') 625 | a.add @jFloat.valueOf('4.5') 626 | a.add @jBoolean.TRUE 627 | a.add @jByte.valueOf('5') 628 | a.add @jLong.valueOf('8070450532247928832') 629 | a.add @jChar.valueOf("A".sum) 630 | assert_equal 'abcdef', a.get(0) 631 | assert_equal 1, a.get(1) 632 | assert_equal 2, a.get(2) 633 | assert_equal 3.1, a.get(3) 634 | assert_equal 4.5, a.get(4) 635 | assert a.get(5) 636 | assert_equal 5, a.get(6) 637 | assert_equal 8070450532247928832, a.get(7) 638 | assert_equal "A".sum, a.get(8) 639 | end 640 | 641 | def test_enum 642 | t = Rjb::import('jp.co.infoseek.hp.arton.rjb.Test$TestTypes') 643 | assert t.ONE.equals(t.values()[0]) 644 | assert_equal 3, t.values().size 645 | assert_equal 2, t.THREE.ordinal 646 | assert_equal "TWO", t.TWO.name 647 | assert_equal "THREE", t.THREE.toString 648 | end 649 | 650 | #rjb-bugs-15430 rebported by Bryan Duxbury 651 | def test_generics_map 652 | 653 | ctest = import('jp.co.infoseek.hp.arton.rjb.Test') 654 | test = ctest.new 655 | map = test.sorted_map 656 | assert_equal "\0\x1\x2\x3\x4", map.get('abc') 657 | assert_equal "\x5\x6\x7\x8\x9", map.get('def') 658 | 659 | cmap = import('java.util.TreeMap') 660 | map = cmap.new 661 | map.put('abc', @jString.new('abc').bytes) 662 | map.put('012', @jString.new('012').bytes) 663 | 664 | Rjb::primitive_conversion = true 665 | map2 = test.throughSortedMap(map) 666 | assert_equal '012', map2.get('012') 667 | assert_equal 'abc', map2.get('abc') 668 | end 669 | 670 | def x_test_zzunload 671 | # this test should run at the last 672 | unload 673 | begin 674 | load('.') 675 | fail 'no exception' 676 | rescue 677 | assert_equal "can't create Java VM", $!.message 678 | end 679 | end 680 | 681 | module TestMixin 682 | def test_hello(s) 683 | 'hello ' + s 684 | end 685 | end 686 | def test_extend 687 | @jString.class_eval do 688 | include TestRjb::TestMixin 689 | end 690 | s = @jString.new 691 | assert_equal('hello world', s.test_hello('world')) 692 | end 693 | def test_extend_with_factory 694 | point = import('java.awt.Point') 695 | point.class_eval do 696 | include TestRjb::TestMixin 697 | end 698 | p = point.new(11, 12) 699 | assert_equal(11, p.x) 700 | assert_equal(12, p.y) 701 | assert_equal('hello world', p.test_hello('world')) 702 | p = p.location 703 | assert_equal(11, p.x) 704 | assert_equal(12, p.y) 705 | assert_equal('hello world', p.test_hello('world')) 706 | end 707 | def test_fetch_method_signature 708 | expected = ['I', 'II', 'Ljava.lang.String;', 'Ljava.lang.String;I'] 709 | sig = @jString.sigs('indexOf').sort 710 | assert_equal(expected, sig) 711 | end 712 | def test_fetch_method_without_signature 713 | sig = 714 | assert_equal([nil], @jString.sigs('toString')) 715 | end 716 | def test_fetch_static_method_signature 717 | expected = ['Ljava.lang.String;[Ljava.lang.Object;', 718 | 'Ljava.util.Locale;Ljava.lang.String;[Ljava.lang.Object;'] 719 | sig = @jString.static_sigs('format').sort 720 | assert_equal(expected, sig) 721 | end 722 | def test_fetch_ctor_signature 723 | expected = ['I', 'Ljava.lang.String;'] 724 | sig = @jInteger.ctor_sigs.sort 725 | assert_equal(expected, sig) 726 | end 727 | def test_methods_extension 728 | m = @jString.new('').methods 729 | assert m.include?(:indexOf) 730 | end 731 | def test_class_methods_extension 732 | m = @jString.methods 733 | assert m.include?(:format) 734 | end 735 | def test_pmethods_extension 736 | m = @jString.new('').public_methods 737 | assert m.include?(:indexOf) 738 | end 739 | def test_class_pmethods_extension 740 | m = @jString.public_methods 741 | assert m.include?(:format) 742 | end 743 | def test_java_methods 744 | indexof = @jString.new('').java_methods.find do |m| 745 | m =~ /^indexOf/ 746 | end 747 | args = indexof.match(/\[([^\]]+)\]/)[1] 748 | assert_equal('Ljava.lang.String;I, II, I, Ljava.lang.String;'.split(/,\s*/).sort, 749 | args.split(/,\s*/).sort) 750 | end 751 | def test_java_class_methods 752 | format = @jString.java_methods.find do |m| 753 | m =~ /^format/ 754 | end 755 | args = format.match(/\[([^\]]+)\]/)[1] 756 | assert_equal('Ljava.lang.String;[Ljava.lang.Object;, Ljava.util.Locale;Ljava.lang.String;[Ljava.lang.Object;'.split(/,\s*/).sort, args.split(/,\s*/).sort) 757 | end 758 | def test_64fixnum 759 | big = @jLong.new_with_sig('J', 1230918239495) 760 | assert_equal 1230918239495, big.long_value 761 | end 762 | def test_add_jar 763 | add_jar(File.expand_path('./jartest.jar')) 764 | jt = import('jp.co.infoseek.hp.arton.rjb.JarTest') 765 | assert jt 766 | assert_equal 'abcd', jt.new.add('ab', 'cd') 767 | end 768 | def test_add_jars 769 | arg = ['./jartest.jar', './jartest.jar'].map do |e| 770 | File.expand_path(e) 771 | end 772 | add_jar(arg) 773 | jt = import('jp.co.infoseek.hp.arton.rjb.JarTest') 774 | assert_equal 'abcd', jt.new.add('ab', 'cd') 775 | end 776 | def test_bothdirection_buffer 777 | org = "abcdefghijklmn" 778 | baip = import('java.io.ByteArrayInputStream') 779 | ba = baip.new(org) 780 | buff = "\0" * org.size 781 | assert_equal org.size, ba.read(buff) 782 | assert_equal -1, ba.read(buff) 783 | ba.close 784 | assert_equal org, buff 785 | end 786 | def test_anoninterface 787 | arrays = import('java.util.Arrays') 788 | a = [3, -4, 5, -6, 8, -10, -14] 789 | index = arrays.binary_search(a, 6) do |m, o1, o2| 790 | o1.abs - o2.abs 791 | end 792 | assert_equal 3, index 793 | index = arrays.binary_search(a, 7) do |m, o1, o2| 794 | o1.abs - o2.abs 795 | end 796 | assert_equal -5, index 797 | end 798 | def test_impl 799 | two = import('jp.co.infoseek.hp.arton.rjb.Two') 800 | t = two.impl { |m| m.to_s } 801 | a = import('jp.co.infoseek.hp.arton.rjb.TwoCaller').new 802 | ret = a.foo(t) 803 | assert_equal 'method1', ret[0] 804 | assert_equal 'method2', ret[1] 805 | end 806 | 807 | def cause_exception 808 | begin 809 | @jInteger.parseInt('blabla') 810 | rescue NumberFormatException => e 811 | raise 812 | end 813 | end 814 | 815 | def test_reraise_exception() 816 | skip('1.8 does not support reraise') if /^1\.8/ =~ RUBY_VERSION 817 | begin 818 | cause_exception 819 | rescue 820 | assert($!.inspect =~ /NumberFormatException/) 821 | end 822 | end 823 | 824 | 825 | def test_inner_exception 826 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 827 | begin 828 | test.cause_exception 829 | flunk("no exception") 830 | rescue IllegalStateException => e 831 | ia = e.cause 832 | assert_equal('bad argument', ia.message) 833 | assert_equal('java.lang.IllegalArgumentException', ia._classname) 834 | end 835 | end 836 | 837 | class CbTest 838 | def method(l, s, i, d, str) 839 | "test_ok:#{l}-#{s}-#{i}-#{d}-#{str}" 840 | end 841 | end 842 | def test_longcallback() 843 | cb = bind(CbTest.new, 'jp.co.infoseek.hp.arton.rjb.CallbackTest$Callback') 844 | test = import('jp.co.infoseek.hp.arton.rjb.CallbackTest') 845 | assert_equal 'test_ok:1234-1234-1234-1234.5-1234', test.callCallback(cb) 846 | end 847 | 848 | class TestIterEx < TestIter 849 | def initialize() 850 | super 851 | @strattr = 'strattr' 852 | @numattr = 32 853 | end 854 | attr_accessor :strattr, :numattr 855 | def multargs(a, b) 856 | a + b 857 | end 858 | end 859 | def test_method_otherthan_bound() 860 | it = TestIterEx.new 861 | it = bind(it, 'java.util.Iterator') 862 | test = import('jp.co.infoseek.hp.arton.rjb.Test') 863 | a = test.new 864 | assert_equal("43210", a.concat(it)) 865 | assert(it.respond_to?(:numattr)) 866 | assert(it.respond_to?(:multargs)) 867 | assert_equal(32, it.numattr) 868 | assert_equal('strattr', it.strattr) 869 | it.numattr += 1 870 | assert_equal(33, it.numattr) 871 | assert_equal(5, it.multargs(3, 2)) 872 | end 873 | def test_noarg_invoke() 874 | str = @jString.new('abc') 875 | assert_equal('abc', str._invoke('toString', '')) 876 | assert_equal('abc', str._invoke('toString', nil)) 877 | assert_equal('abc', str._invoke('toString')) 878 | end 879 | def test_noarg_sinvoke() 880 | loader= import('java.lang.ClassLoader') 881 | sloader = loader.system_class_loader 882 | assert_equal(sloader._classname, loader._invoke('getSystemClassLoader', '')._classname) 883 | assert_equal(sloader._classname, loader._invoke('getSystemClassLoader', nil)._classname) 884 | assert_equal(sloader._classname, loader._invoke('getSystemClassLoader')._classname) 885 | end 886 | def test_longarg 887 | skip('rbx can handle 64bits long') if RUBY_ENGINE == 'rbx' 888 | assert_equal(597899502607411822, @jLong.reverse(0x7654321076543210)) 889 | begin 890 | @jLong.reverse(0x76543210765432101) 891 | fail 'no exception for bigbnum it doesn\'t convert Java long' 892 | rescue RangeError 893 | assert true 894 | end 895 | end 896 | def test_bytearg 897 | b = @jByte.new(32) 898 | assert_equal(32, b.int_value) 899 | assert b.compareTo(@jByte.new(32)) 900 | assert b.compareTo(@jByte.value_of(32)) 901 | b = @jByte.new_with_sig('B', 32) 902 | assert_equal(32, b.int_value) 903 | assert b.compareTo(@jByte._invoke(:valueOf, 'B', 32)) 904 | end 905 | def test_typedarray 906 | test = import('jp.co.infoseek.hp.arton.rjb.Test').new 907 | uri = import('java.net.URI') 908 | ret = test.java_typed_array(['a', 'b', 'c'], [1, 2, 3], [uri.new('http://www.artonx.org')]) 909 | assert_equal '[Ljava.lang.String;', ret[0] 910 | assert_equal '[Ljava.lang.Integer;', ret[1] 911 | assert_equal '[Ljava.net.URI;', ret[2] 912 | end 913 | 914 | SJIS_STR = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" 915 | EUCJP_STR = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8" 916 | UTF8_STR = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" 917 | def test_auto_constructor_selection 918 | skip 'no encoding' unless Object::const_defined?(:Encoding) 919 | sys = import('java.lang.System') 920 | encoding = sys.property('file.encoding') 921 | s = @jString.new(SJIS_STR.force_encoding Encoding::SHIFT_JIS) 922 | e = @jString.new(EUCJP_STR.force_encoding Encoding::EUC_JP) 923 | u = @jString.new(UTF8_STR.force_encoding Encoding::UTF_8) 924 | if encoding == 'MS932' 925 | s1 = @jString.new(SJIS_STR.bytes) 926 | elsif encoding.upcase == 'EUC-JP' 927 | s1 = @jString.new(EUCJP_STR.bytes) 928 | elsif encoding.upcase == 'UTF-8' 929 | s1 = @jString.new(UTF8_STR.bytes) 930 | else 931 | skip 'no checkable encoding' 932 | end 933 | assert_equal s1.toString, s.toString 934 | assert_equal s1.toString, e.toString 935 | assert_equal s1.toString, u.toString 936 | end 937 | 938 | def test_bothdirection_chararray 939 | charArrayReader = import('java.io.CharArrayReader') 940 | org = [48, 49, 50, 51, 52, 53] 941 | reader = charArrayReader.new(org) 942 | buffer = Array.new(32, 0) 943 | len = reader.read(buffer, 0, buffer.size) 944 | assert_equal org.size, len 945 | assert_equal org, buffer[0...len] 946 | end 947 | 948 | def test_re_raise 949 | begin 950 | @jInteger.parseInt('blabla') 951 | flunk('no exception') 952 | rescue NumberFormatException => e 953 | begin 954 | raise 955 | rescue => e 956 | assert_equal(NumberFormatException, e.class) 957 | # OK 958 | end 959 | end 960 | end 961 | 962 | def test_java_utf8 963 | y = @jString.new('𠮷野家') # with surrogate pair 964 | assert_equal '𠮷野家', y.toString 965 | end 966 | 967 | def test_java_hangul_syllable 968 | # 토 \uD1A => ED 86 A0 (utf-8) 969 | test_string = "토" # simple unicode char (not surrogate pair) 970 | y = @jString.new_with_sig('Ljava.lang.String;', test_string) 971 | assert_equal(test_string, y.toString) 972 | test_string = "토토" # simple unicode char (not surrogate pair) 973 | y = @jString.new_with_sig('Ljava.lang.String;', test_string) 974 | assert_equal(test_string, y.toString) 975 | end 976 | 977 | def test_respond_to 978 | str = @jString.new('blabla') 979 | assert str.respond_to? :substring 980 | assert_false str.respond_to? :unknown_method 981 | begin 982 | @jInteger.parseInt('blabla') 983 | rescue => e 984 | assert e.respond_to? :print_stack_trace 985 | assert e.respond_to? :printStackTrace 986 | assert_false e.respond_to? :unknown_method 987 | end 988 | end 989 | 990 | def test_load_nested_class_as_java_convention 991 | tstate = import('java.lang.Thread.State') 992 | assert_equal(tstate.BLOCKED.ordinal, 2) 993 | assert_equal(tstate.BLOCKED.name, 'BLOCKED') 994 | end 995 | 996 | def test_load_inner_class_as_java_convention 997 | tes = import('java.util.HashMap.EntrySet') 998 | assert_equal(tes._classname, 'java.lang.Class') 999 | end 1000 | end 1001 | -------------------------------------------------------------------------------- /test/test105.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require 'rjb' 3 | rescue LoadError 4 | require 'rubygems' 5 | require 'rjb' 6 | end 7 | require 'test/unit' 8 | 9 | class Test105 < Test::Unit::TestCase 10 | include Rjb 11 | def setup 12 | Rjb::load('.') 13 | @test105 = import('jp.co.infoseek.hp.arton.rjb.Test105') 14 | end 15 | 16 | def test_field 17 | test = @test105.new('xyz') 18 | assert_equal('xyz', test.test) 19 | end 20 | 21 | def test_method 22 | test = @test105.new('xyz') 23 | ret = test._invoke('test') 24 | assert_equal('method_xyz', ret) 25 | end 26 | end 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/test_osxjvm.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | # $Id:$ 4 | 5 | begin 6 | require 'rjb' 7 | rescue LoadError 8 | require 'rubygems' 9 | require 'rjb' 10 | end 11 | require 'test/unit' 12 | 13 | if RUBY_PLATFORM =~ /darwin/ 14 | class TestOsxJvm < Test::Unit::TestCase 15 | def test_with_javahome 16 | ENV['JAVA_HOME'] = `/usr/libexec/java_home` 17 | assert_nothing_raised do 18 | Rjb::load 19 | end 20 | end 21 | end 22 | end 23 | 24 | -------------------------------------------------------------------------------- /test/test_osxload.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | require 'rbconfig' 4 | require 'test/unit' 5 | 6 | class TestOSXLoad < Test::Unit::TestCase 7 | def setup 8 | ENV['JAVA_HOME'] = '' 9 | ENV['JVM_LIB'] = '' 10 | @testprog = File.dirname($0) + File::SEPARATOR + 'osx_jvmcheck.rb' 11 | end 12 | 13 | def test_no_java_home 14 | skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM 15 | 16 | javahome = `/usr/libexec/java_home` 17 | if javahome =~ /jdk1\.[7-8]\.0/ 18 | vendor = /Oracle/ 19 | version = /1\.[7-8]\.0/ 20 | else 21 | vendor = /Apple/ 22 | version = /1\.[4-6]\.0/ 23 | end 24 | test = `#{RbConfig.ruby} #{@testprog}` 25 | assert test =~ vendor, expected(vendor, test) 26 | assert test =~ version, expected(version, test) 27 | end 28 | 29 | def test_apple_jvm 30 | skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM 31 | 32 | test_specific_jvm('/System/Library/Frameworks/JavaVM.framework/Home', 33 | /Apple/) 34 | end 35 | 36 | def test_oracle_jvm 37 | skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM 38 | 39 | test_specific_jvm('/Library/Java/JavaVirtualMachines/***/Contents/Home', 40 | /Oracle/) 41 | end 42 | 43 | def test_withjvmlib 44 | skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM 45 | 46 | ENV['JVM_LIB'] = '/usr/lib/libc.dylib' 47 | test = `#{RbConfig.ruby} #{@testprog}`.strip 48 | assert test == '', "no exception but #{test}" 49 | end 50 | 51 | private 52 | def test_specific_jvm(path, vendor) 53 | jvms = Dir.glob(path) 54 | skip "no #{vendor.inspect} jvm" if jvms.size == 0 55 | ENV['JAVA_HOME'] = jvms[0] 56 | test = `#{RbConfig.ruby} #{@testprog}`.strip 57 | assert test =~ vendor, expected(vendor, test) 58 | end 59 | 60 | def expected(test, target) 61 | "expected #{test.inspect} but #{target}" 62 | end 63 | end 64 | 65 | -------------------------------------------------------------------------------- /test/test_unload.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/env ruby -Ku 2 | # encoding: utf-8 3 | # $Id: test.rb 176 2011-11-09 14:27:28Z arton $ 4 | 5 | begin 6 | require 'rjb' 7 | rescue LoadError 8 | require 'rubygems' 9 | require 'rjb' 10 | end 11 | require 'test/unit' 12 | 13 | class TestUnloadRjb < Test::Unit::TestCase 14 | include Rjb 15 | def setup 16 | Rjb::load('.') 17 | end 18 | 19 | def test_unload 20 | jString = import('java.lang.String') 21 | assert_equal 0, Rjb::unload 22 | jString = nil 23 | GC.start 24 | end 25 | end 26 | 27 | --------------------------------------------------------------------------------