[[The 48 Laws of Power|http://www2.tech.purdue.edu/cgt/courses/cgt411/covey/48_laws_of_power.htm]]\nby Robert Greene and Joost Elffers\n\n\n!Law 1- Never Outshine the Master\n\nAlways make those above you feel comfortably superior. In your desire to please or impress them, do not go too far in displaying your talents or you might accomplish the opposite – inspire fear and insecurity. Make your masters appear more brilliant than they are and you will attain the heights of power.\n\n!Law 2- Never put too Much Trust in Friends, Learn how to use Enemies\n\nBe wary of friends-they will betray you more quickly, for they are easily aroused to envy. They also become spoiled and tyrannical. But hire a former enemy and he will be more loyal than a friend, because he has more to prove. In fact, you have more to fear from friends than from enemies. If you have no enemies, find a way to make them.\n\n Law 3\n\nConceal your Intentions\n\nKeep people off-balance and in the dark by never revealing the purpose behind your actions. If they have no clue what you are up to, they cannot prepare a defense. Guide them far enough down the wrong path, envelope them in enough smoke, and by the time they realize your intentions, it will be too late.\n\n Law 4\n\nAlways Say Less than Necessary\n\nWhen you are trying to impress people with words, the more you say, the more common you appear, and the less in control. Even if you are saying something banal, it will seem original if you make it vague, open-ended, and sphinxlike. Powerful people impress and intimidate by saying less. The more you say, the more likely you are to say something foolish.\n\n Law 5\n\nSo Much Depends on Reputation – Guard it with your Life\n\nReputation is the cornerstone of power. Through reputation alone you can intimidate and win; once you slip, however, you are vulnerable, and will be attacked on all sides. Make your reputation unassailable. Always be alert to potential attacks and thwart them before they happen. Meanwhile, learn to destroy your enemies by opening holes in their own reputations. Then stand aside and let public opinion hang them.\n\n Law 6\n\nCourt Attention at all Cost\n\nEverything is judged by its appearance; what is unseen counts for nothing. Never let yourself get lost in the crowd, then, or buried in oblivion. Stand out. Be conspicuous, at all cost. Make yourself a magnet of attention by appearing larger, more colorful, more mysterious, than the bland and timid masses.\n\n Law 7\n\nGet others to do the Work for you, but Always Take the Credit\n\nUse the wisdom, knowledge, and legwork of other people to further your own cause. Not only will such assistance save you valuable time and energy, it will give you a godlike aura of efficiency and speed. In the end your helpers will be forgotten and you will be remembered. Never do yourself what others can do for you.\n\n Law 8\n\nMake other People come to you – use Bait if Necessary\n\nWhen you force the other person to act, you are the one in control. It is always better to make your opponent come to you, abandoning his own plans in the process. Lure him with fabulous gains – then attack. You hold the cards.\n\n Law 9\n\nWin through your Actions, Never through Argument\n\nAny momentary triumph you think gained through argument is really a Pyrrhic victory: The resentment and ill will you stir up is stronger and lasts longer than any momentary change of opinion. It is much more powerful to get others to agree with you through your actions, without saying a word. Demonstrate, do not explicate.\n\n Law 10\n\nInfection: Avoid the Unhappy and Unlucky\n\nYou can die from someone else’s misery – emotional states are as infectious as disease. You may feel you are helping the drowning man but you are only precipitating your own disaster. The unfortunate sometimes draw misfortune on themselves; they will also draw it on you. Associate with the happy and fortunate instead.\n\nLaw 11\n\nLearn to Keep People Dependent on You\n\nTo maintain your independence you must always be needed and wanted. The more you are relied on, the more freedom you have. Make people depend on you for their happiness and prosperity and you have nothing to fear. Never teach them enough so that they can do without you.\n\n Law 12\n\nUse Selective Honesty and Generosity to Disarm your Victim\n\nOne sincere and honest move will cover over dozens of dishonest ones. Open-hearted gestures of honesty and generosity bring down the guard of even the most suspicious people. Once your selective honesty opens a hole in their armor, you can deceive and manipulate them at will. A timely gift – a Trojan horse – will serve the same purpose.\n\n Law 13\n\nWhen Asking for Help, Appeal to People’s Self-Interest,\n\nNever to their Mercy or Gratitude\n\nIf you need to turn to an ally for help, do not bother to remind him of your past assistance and good deeds. He will find a way to ignore you. Instead, uncover something in your request, or in your alliance with him, that will benefit him, and emphasize it out of all proportion. He will respond enthusiastically when he sees something to be gained for himself.\n\n Law 14\n\nPose as a Friend, Work as a Spy\n\nKnowing about your rival is critical. Use spies to gather valuable information that will keep you a step ahead. Better still: Play the spy yourself. In polite social encounters, learn to probe. Ask indirect questions to get people to reveal their weaknesses and intentions. There is no occasion that is not an opportunity for artful spying.\n\n Law 15\n\nCrush your Enemy Totally\n\nAll great leaders since Moses have known that a feared enemy must be crushed completely. (Sometimes they have learned this the hard way.) If one ember is left alight, no matter how dimly it smolders, a fire will eventually break out. More is lost through stopping halfway than through total annihilation: The enemy will recover, and will seek revenge. Crush him, not only in body but in spirit.\n\n Law 16\n\nUse Absence to Increase Respect and Honor\n\nToo much circulation makes the price go down: The more you are seen and heard from, the more common you appear. If you are already established in a group, temporary withdrawal from it will make you more talked about, even more admired. You must learn when to leave. Create value through scarcity.\n\n Law 17\n\nKeep Others in Suspended Terror: Cultivate an Air of Unpredictability\n\nHumans are creatures of habit with an insatiable need to see familiarity in other people’s actions. Your predictability gives them a sense of control. Turn the tables: Be deliberately unpredictable. Behavior that seems to have no consistency or purpose will keep them off-balance, and they will wear themselves out trying to explain your moves. Taken to an extreme, this strategy can intimidate and terrorize.\n\n Law 18\n\nDo Not Build Fortresses to Protect Yourself – Isolation is Dangerous\n\nThe world is dangerous and enemies are everywhere – everyone has to protect themselves. A fortress seems the safest. But isolation exposes you to more dangers than it protects you from – it cuts you off from valuable information, it makes you conspicuous and an easy target. Better to circulate among people find allies, mingle. You are shielded from your enemies by the crowd.\n\n Law 19\n\nKnow Who You’re Dealing with – Do Not Offend the Wrong Person\n\nThere are many different kinds of people in the world, and you can never assume that everyone will react to your strategies in the same way. Deceive or outmaneuver some people and they will spend the rest of their lives seeking revenge. They are wolves in lambs’ clothing. Choose your victims and opponents carefully, then – never offend or deceive the wrong person.\n\n Law 20\n\nDo Not Commit to Anyone\n\nIt is the fool who always rushes to take sides. Do not commit to any side or cause but yourself. By maintaining your independence, you become the master of others – playing people against one another, making them pursue you.\n\n Law 21\n\nPlay a Sucker to Catch a Sucker – Seem Dumber than your Mark\n\nNo one likes feeling stupider than the next persons. The trick, is to make your victims feel smart – and not just smart, but smarter than you are. Once convinced of this, they will never suspect that you may have ulterior motives.\n\n Law 22\n\nUse the Surrender Tactic: Transform Weakness into Power\n\nWhen you are weaker, never fight for honor’s sake; choose surrender instead. Surrender gives you time to recover, time to torment and irritate your conqueror, time to wait for his power to wane. Do not give him the satisfaction of fighting and defeating you – surrender first. By turning the other check you infuriate and unsettle him. Make surrender a tool of power.\n\n Law 23\n\nConcentrate Your Forces\n\nConserve your forces and energies by keeping them concentrated at their strongest point. You gain more by finding a rich mine and mining it deeper, than by flitting from one shallow mine to another – intensity defeats extensity every time. When looking for sources of power to elevate you, find the one key patron, the fat cow who will give you milk for a long time to come.\n\n Law 24\n\nPlay the Perfect Courtier\n\nThe perfect courtier thrives in a world where everything revolves around power and political dexterity. He has mastered the art of indirection; he flatters, yields to superiors, and asserts power over others in the mot oblique and graceful manner. Learn and apply the laws of courtiership and there will be no limit to how far you can rise in the court.\n\n Law 25\n\nRe-Create Yourself\n\nDo not accept the roles that society foists on you. Re-create yourself by forging a new identity, one that commands attention and never bores the audience. Be the master of your own image rather than letting others define if for you. Incorporate dramatic devices into your public gestures and actions – your power will be enhanced and your character will seem larger than life.\n\n Law 26\n\nKeep Your Hands Clean\n\nYou must seem a paragon of civility and efficiency: Your hands are never soiled by mistakes and nasty deeds. Maintain such a spotless appearance by using others as scapegoats and cat’s-paws to disguise your involvement.\n\nLaw 27\n\nPlay on People’s Need to Believe to Create a Cultlike Following\n\nPeople have an overwhelming desire to believe in something. Become the focal point of such desire by offering them a cause, a new faith to follow. Keep your words vague but full of promise; emphasize enthusiasm over rationality and clear thinking. Give your new disciples rituals to perform, ask them to make sacrifices on your behalf. In the absence of organized religion and grand causes, your new belief system will bring you untold power.\n\n Law 28\n\nEnter Action with Boldness\n\nIf you are unsure of a course of action, do not attempt it. Your doubts and hesitations will infect your execution. Timidity is dangerous: Better to enter with boldness. Any mistakes you commit through audacity are easily corrected with more audacity. Everyone admires the bold; no one honors the timid.\n\n Law 29\n\nPlan All the Way to the End\n\nThe ending is everything. Plan all the way to it, taking into account all the possible consequences, obstacles, and twists of fortune that might reverse your hard work and give the glory to others. By planning to the end you will not be overwhelmed by circumstances and you will know when to stop. Gently guide fortune and help determine the future by thinking far ahead.\n\n Law 30\n\nMake your Accomplishments Seem Effortless\n\nYour actions must seem natural and executed with ease. All the toil and practice that go into them, and also all the clever tricks, must be concealed. When you act, act effortlessly, as if you could do much more. Avoid the temptation of revealing how hard you work – it only raises questions. Teach no one your tricks or they will be used against you.\n\n Law 31\n\nControl the Options: Get Others to Play with the Cards you Deal\n\nThe best deceptions are the ones that seem to give the other person a choice: Your victims feel they are in control, but are actually your puppets. Give people options that come out in your favor whichever one they choose. Force them to make choices between the lesser of two evils, both of which serve your purpose. Put them on the horns of a dilemma: They are gored wherever they turn.\n\n Law 32\n\nPlay to People’s Fantasies\n\nThe truth is often avoided because it is ugly and unpleasant. Never appeal to truth and reality unless you are prepared for the anger that comes for disenchantment. Life is so harsh and distressing that people who can manufacture romance or conjure up fantasy are like oases in the desert: Everyone flocks to them. There is great power in tapping into the fantasies of the masses.\n\n Law 33\n\nDiscover Each Man’s Thumbscrew\n\nEveryone has a weakness, a gap in the castle wall. That weakness is usual y an insecurity, an uncontrollable emotion or need; it can also be a small secret pleasure. Either way, once found, it is a thumbscrew you can turn to your advantage.\n\n Law 34\n\nBe Royal in your Own Fashion: Act like a King to be treated like one\n\nThe way you carry yourself will often determine how you are treated; In the long run, appearing vulgar or common will make people disrespect you. For a king respects himself and inspires the same sentiment in others. By acting regally and confident of your powers, you make yourself seem destined to wear a crown.\n\n Law 35\n\nMaster the Art of Timing\n\nNever seem to be in a hurry – hurrying betrays a lack of control over yourself, and over time. Always seem patient, as if you know that everything will come to you eventually. Become a detective of the right moment; sniff out the spirit of the times, the trends that will carry you to power. Learn to stand back when the time is not yet ripe, and to strike fiercely when it has reached fruition.\n\n Law 36\n\nDisdain Things you cannot have: Ignoring them is the best Revenge\n\nBy acknowledging a petty problem you give it existence and credibility. The more attention you pay an enemy, the stronger you make him; and a small mistake is often made worse and more visible when you try to fix it. It is sometimes best to leave things alone. If there is something you want but cannot have, show contempt for it. The less interest you reveal, the more superior you seem. \n\nLaw 37\n\nCreate Compelling Spectacles\n\nStriking imagery and grand symbolic gestures create the aura of power – everyone responds to them. Stage spectacles for those around you, then full of arresting visuals and radiant symbols that heighten your presence. Dazzled by appearances, no one will notice what you are really doing.\n\nLaw 38\n\nThink as you like but Behave like others\n\nIf you make a show of going against the times, flaunting your unconventional ideas and unorthodox ways, people will think that you only want attention and that you look down upon them. They will find a way to punish you for making them feel inferior. It is far safer to blend in and nurture the common touch. Share your originality only with tolerant friends and those who are sure to appreciate your uniqueness.\n\nLaw 39\n\nStir up Waters to Catch Fish\n\nAnger and emotion are strategically counterproductive. You must always stay calm and objective. But if you can make your enemies angry while staying calm yourself, you gain a decided advantage. Put your enemies off-balance: Find the chink in their vanity through which you can rattle them and you hold the strings.\n\nLaw 40\n\nDespise the Free Lunch\n\nWhat is offered for free is dangerous – it usually involves either a trick or a hidden obligation. What has worth is worth paying for. By paying your own way you stay clear of gratitude, guilt, and deceit. It is also often wise to pay the full price – there is no cutting corners with excellence. Be lavish with your money and keep it circulating, for generosity is a sign and a magnet for power.\n\nLaw 41\n\nAvoid Stepping into a Great Man’s Shoes\n\nWhat happens first always appears better and more original than what comes after. If you succeed a great man or have a famous parent, you will have to accomplish double their achievements to outshine them. Do not get lost in their shadow, or stuck in a past not of your own making: Establish your own name and identity by changing course. Slay the overbearing father, disparage his legacy, and gain power by shining in your own way.\n\nLaw 42\n\nStrike the Shepherd and the Sheep will Scatter\n\nTrouble can often be traced to a single strong individual – the stirrer, the arrogant underling, the poisoned of goodwill. If you allow such people room to operate, others will succumb to their influence. Do not wait for the troubles they cause to multiply, do not try to negotiate with them – they are irredeemable. Neutralize their influence by isolating or banishing them. Strike at the source of the trouble and the sheep will scatter.\n\nLaw 43\n\nWork on the Hearts and Minds of Others\n\nCoercion creates a reaction that will eventually work against you. You must seduce others into wanting to move in your direction. A person you have seduced becomes your loyal pawn. And the way to seduce others is to operate on their individual psychologies and weaknesses. Soften up the resistant by working on their emotions, playing on what they hold dear and what they fear. Ignore the hearts and minds of others and they will grow to hate you.\n\nLaw 44\n\nDisarm and Infuriate with the Mirror Effect\n\nThe mirror reflects reality, but it is also the perfect tool for deception: When you mirror your enemies, doing exactly as they do, they cannot figure out your strategy. The Mirror Effect mocks and humiliates them, making them overreact. By holding up a mirror to their psyches, you seduce them with the illusion that you share their values; by holding up a mirror to their actions, you teach them a lesson. Few can resist the power of Mirror Effect.\n\nLaw 45\n\nPreach the Need for Change, but Never Reform too much at Once\n\nEveryone understands the need for change in the abstract, but on the day-to-day level people are creatures of habit. Too much innovation is traumatic, and will lead to revolt. If you are new to a position of power, or an outsider trying to build a power base, make a show of respecting the old way of doing things. If change is necessary, make it feel like a gentle improvement on the past.\n\nLaw 46\n\nNever appear too Perfect\n\nAppearing better than others is always dangerous, but most dangerous of all is to appear to have no faults or weaknesses. Envy creates silent enemies. It is smart to occasionally display defects, and admit to harmless vices, in order to deflect envy and appear more human and approachable. Only gods and the dead can seem perfect with impunity.\n\nLaw 47\n\nDo not go Past the Mark you Aimed for; In Victory, Learn when to Stop\n\nThe moment of victory is often the moment of greatest peril. In the heat of victory, arrogance and overconfidence can push you past the goal you had aimed for, and by going too far, you make more enemies than you defeat. Do not allow success to go to your head. There is no substitute for strategy and careful planning. Set a goal, and when you reach it, stop.\n\nLaw 48\n\nAssume Formlessness\n\nBy taking a shape, by having a visible plan, you open yourself to attack. Instead of taking a form for your enemy to grasp, keep yourself adaptable and on the move. Accept the fact that nothing is certain and no law is fixed. The best way to protect yourself is to be as fluid and formless as water; never bet on stability or lasting order. Everything changes.\n\n \n\n \n\n \n\n \n\n \n
!Bill\n* Go over TPS reports\n\n!Milton \n* Get Back Stapler
* Email Michael for another copy of TPS report memo.\n* Call Bobs to set up performance review.
! Digital Organization\n* Look into getting a big magnet\n\n! Organization\n* Get archival boxes for old letters and manuals\n* Plan closet organization\n* Plan office closet organization\n* set up auto billing for credit cards\n\n! Gadgets, Hardware\n* Research Swingline staplers
* Compile list of favorite fonts starting with comic sans\n* Run defrag\n* Read memo about TPS reports\n
! Trader Joes\n* Goat Milk Yogurt\n* Cereal\n\n! Whole Foods\n* Sausage\n* Buns\n\n! Ralphs\n* Toilet Paper\n* Spinach
! Products\n* Look at new home office furniture\n* Look into alternative phone plans \n\n! Movies to see\n* Aliens of the deep\n\n! Music to buy\n* Saint Ettiene (good humor, 2 disc set with "fairfax high")\n* Michael Bolton's greatest hits\n* Cinerama\n\n!! Current Heavy rotation\n* Interpol\n* Franz Ferdinand\n* Killers\n* Postal Service\n\n! Books\n* Check amazon wish list\n\n! Leisure\n* Go Fishing\n\n! Health/Exercise/Food\n* Call gym for yoga class times
>[[开始使用]]\n>>[[安装]]\n>>[[运行]]\n>>[[文档化Ri]]\n>[[Ruby.new]]\n>>[[块和迭代器]]\n>>[[读取/输出]]\n>[[类,对象和变量]]\n>>[[继承]]\n>>[[对象和属性]]\n>>[[类变量]]\n>>[[类方法]]\n>>[[单子]]\n>>[[访问控制]]\n>>[[变量]]\n>[[容器、块和迭代]]\n>>[[容器]]\n>>[[块和迭代]]\n>>>[[实现迭代器]]\n>>>[[Ruby和c++,java的比较]]\n>>>[[在事务处理中使用块]]\n>>>[[块和闭包]]\n>[[标准类型]]\n>>[[数字型]]\n>>[[字符串]]\n>>[[运用字符串]]\n>>[[范围]]\n>>[[正则表达式]]\n>[[深入方法]]\n>[[表达式]]\n>>[[操作表达式]]\n>>[[混合表达式]]\n>>[[赋值]]\n>>[[条件执行]]\n>>[[case]]\n>>[[循环]]\n>>[[迭代]]\n>>[[变量作用域和循环]]\n>[[异常、捕捉和抛出]]\n>[[模块]]\n>[[基本输入输出]]\n>[[线程和进程]]
! Office supplies:\n* 2 Big Mouse Pads\n* Zip ties (black)\n* USB hub\n\n! General:\n* Mail outbox letters at post office\n* Pick up dry cleaning
* Learn more PHP\n* Figure out TPS reports\n* Play with Knoppix
* Learn to make sushi\n* Alaska trip
* For code from Samir\n* Email from Bill about TPS reports\n* Milton to turn off the radio
* Organize Firefox Bookmarks\n* Remove door from hinges\n* The fax machine DIES AT DUSK!
GTD Tiddly Wiki is a GettingThingsDone adaptation by NathanBowers of JeremyRuston's Open Source TiddlyWiki. The purpose of GTD Tiddly Wiki is to give users a single repository for their GTD lists and support materials so they can create/edit lists, and then print directly to 3x5 cards for use with the HipsterPDA.\n\n!Features Include:\n* Free and Open Source.\n* Easy to update.\n* Prints directly to 3x5.\n* Searchable.\n* Exists as a single, portable, cross platform file.\n* It runs on your computer, so you can make changes when you're not online. It's not a ServerSide thing.\n!Get started:\nStart by saving GTDTiddlyWiki to your computer (right click on [[this link|#]] and select 'Save link as...' or 'Save target as...' See SaveChanges for details).\n \nYou can edit entries, or "Tidders", by clicking "edit" or double clicking anywhere on the Tiddler. When you click "done" or press [ctrl+enter] your changes are saved.\n\nThere are some pre-populated action lists in the MainMenu on the left. If you want to start with a blank slate, here is an [[empty template|empty.html]].\n\n!!More information:\n*SupportedBrowsers\n*KeyFeatures\n*KeyboardShortcuts\n*[[Print3x5]]\n*FormattingInstructions (create lists, headings, and other formatting)\n*AboutTiddlers\n*CreateTiddlers\n*DeleteTiddlers\n* PermaView\n*KnownBugs\n* HowToUpgrade\n* ServerSide version.\n*Jeremy's original HelloThere.\n\nThanks to JeremyRuston for creating such a great Open Source project!\n----\nTiddlyWiki and GTD Tiddly Wiki are published under an OpenSourceLicense and carry NoWarranty.\n\nCurrent Version: <<version>> | RevisionHistory | UpdateNotification
"Tiddlers" are the building blocks of TiddlyWiki. Each "entry" or "post" is a Tiddler. There are also SpecialTiddlers that control the MainMenu, SiteTitle, SiteSubtitle, and list of DefaultTiddlers that display on start up.
<div class='toolbar'><span macro='closeTiddler'></span><span macro='singleSlideMode'></span><span macro='closeOthers'></span><span macro='editTiddler'></span><span macro='permalink'></span><span macro='references'></span><span macro='jump'></span></div><div class='title' macro='view title'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='footer'>\n<span macro='tags'></span>\n</div>
JeremyRuston said:\n<<<\nA TiddlyWiki is like a blog because it's divided up into neat little chunks, but it encourages you to read it by hyperlinking rather than sequentially: if you like, a non-linear blog analogue that binds the individual microcontent items into a cohesive whole. I think that TiddlyWiki represents a novel medium for writing, and will promote it's own distinctive WritingStyle. This is the first version of TiddlyWiki and so, as discussed in TiddlyWikiDev, it's bound to be FullOfBugs, have many MissingFeatures and fail to meet all of the DesignGoals. And of course there's NoWarranty, and it might be judged a StupidName.\n<<<\n\n>level 1\n>level 1\n>>level 2\n>>level 2\n>>>level 3\n>>>level 3\n>>level 2\n>level 1\n
This ThirdVersion of TiddlyWiki fixes a problem with line breaks within tiddlers under InternetExplorer. It also tries to avoid closing tiddlers while they are being edited. There's a bunch of smaller BugFixes as well, but they are somewhat balanced by the KnownBugs.
Edit this tiddler to see how to create BulletPoints\n* Like this one\n* And this one\n** And this second-level one\n* And a final one
/***\n''CheckboxPlugin for TiddlyWiki version 1.2.39''\n^^author: Eric Shulman\nsource: http://www.elsdesign.com/tiddlywiki/#CheckboxPlugin \nlicense: [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]^^\n\nAdd checkboxes to your tiddler content. Checkbox states can be preserved in the document (by automatically modifying the tiddler content), or saved in local cookies by assigning an optional 'id' to the checkbox. Add custom javascript for programmatic initialization and onClick handling for any checkbox. Also provides access to checkbox DOM element data and tracks the checkbox state in TiddlyWiki's config.options[] internal data.\n\n''This is a BETA release. Syntax and functionality are subject to change''\n\nFor more details, please click on a section headline below:\n++++!!!!![Usage]>\n//{{{\n[ ]or[_] and [x]or[X]\n//}}}\n\n[X] check me!\n\nSimple checkboxes. The current unchecked/checked state is indicated by the character between the {{{[}}} and {{{]}}} brackets ("_" means unchecked, "X" means checked). When you click on a checkbox, the current state is retained by directly modifying the tiddler content to place the corresponding "_" or "X" character in between the brackets\n//{{{\n[x]=id\n//}}}\nAssign an optional ID to the checkbox so you can use {{{document.getElementByID("id")}}} to manipulate the checkbox DOM element, as well as tracking the current checkbox state in {{{config.options["id"]}}}. If the ID starts with "chk" the checkbox state will also be saved in a cookie, so it can be automatically restored whenever the checkbox is re-rendered (overrides any default {{{[x]}}} or {{{[_]}}} value). If a cookie value is kept, the "_" or "X" character in the tiddler content remains unchanged, and is only applied as the default when a cookie-based value is not currently defined.\n//{{{\n[x]=id{javascript}{javascript}\n//}}}\nYou can define optional javascript code segments to add custom initialization and/or 'onClick' handling to a checkbox. The current checkbox state (and it's other DOM attributes) can be set or read from within these code segments by reference to the default context-object, 'this'.\n\nThe first code segment will be executed when the checkbox is initially displayed, so that you can programmatically determine it's starting checked/unchecked state. The second code segment (if present) is executed whenever the checkbox is clicked, so that you can perform programmed responses or intercept and override the checkbox state based on complex logic using the TW core API or custom functions defined in plugins (e.g. testing a particular tiddler title to see if certain tags are set or setting some tags when the checkbox is clicked).\n\nNote: if you want to use the default checkbox initialization processing with a custom onclick function, use this syntax: {{{ [x]=id{}{javascript} }}} \n===\n++++!!!!![Examples]>\n{{{ [x] and [_] checked and unchecked default values }}}\n[ ] and [X] checked and unchecked static default values\n\n{{{ [_]=demo document-based value (no cookie) }}}\n[_]=demo document-based value (no cookie)\n\n{{{ [_]=chkDemo cookie-based value}}}\n[_]=chkDemo cookie-based value\n\n{{{ [_]=demo2{this.checked=true}{this.checked=confirm("override checkbox:\sn\snOK=checked, Cancel=unchecked");} function-based value }}}\n[X]=demo2{this.checked=true}{this.checked=confirm("override checkbox:\sn\snOK=checked, Cancel=unchecked");} function-based value\n\nRetrieving option values:\nconfig.options['demo']=<script>return config.options['demo']?"true":"false";</script>\nconfig.options['chkDemo']=<script>return config.options['chkDemo']?"true":"false";</script>\nconfig.options['demo2']=<script>return config.options['demo2']?"true":"false";</script>\n===\n+++!!!!![Installation]>\nimport (or copy/paste) the following tiddlers into your document:\n''CheckboxPlugin'' (tagged with <<tag systemConfig>>)\n===\n+++!!!!![Revision History]>\n++++[2005.12.08 - 0.9.2]\n support separate 'init' and 'onclick' function definitions.\n===\n++++[2005.12.08 - 0.9.2]\n clean up lookahead pattern\n===\n++++[2005.12.07 - 0.9.1]\n only update tiddler source content if checkbox state is actually different. Eliminates unnecessary tiddler changes (and 'unsaved changes' warnings)\n===\n++++[2005.12.07 - 0.9.0]\n initial BETA release\n===\n===\n+++!!!!![Credits]>\nThis feature was created by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]\n===\n***/\n// //++++!!!!![Code]\n//{{{\nversion.extensions.CheckboxPlugin = {major: 0, minor: 9, revision: 3, date: new Date(2005,12,08)};\n//}}}\n\n//{{{\nconfig.formatters.push( {\n name: "checkbox",\n match: "\s\s[[xX_ ]\s\s]",\n lookahead: "\s\s[([xX_ ])\s\s](=[^\s\ss{]+)?({[^}]*})?({[^}]*})?",\n handler: function(w)\n {\n var lookaheadRegExp = new RegExp(this.lookahead,"mg");\n lookaheadRegExp.lastIndex = w.matchStart;\n var lookaheadMatch = lookaheadRegExp.exec(w.source)\n if(lookaheadMatch && lookaheadMatch.index == w.matchStart)\n {\n // get params\n var checked=lookaheadMatch[1];\n var id=lookaheadMatch[2];\n var fn_init=lookaheadMatch[3];\n var fn_click=lookaheadMatch[4];\n // create checkbox element\n var c = document.createElement("input");\n c.setAttribute("type","checkbox");\n c.onclick=onClickCheckbox;\n c.srcpos=w.matchStart+1; // remember location of "X"\n w.output.appendChild(c);\n // set default state\n c.checked=(checked.toUpperCase()=="X");\n // get/set state by ID\n if (id) {\n c.id=id.substr(1); // trim off leading "="\n if (config.options[c.id]!=undefined)\n c.checked=config.options[c.id];\n else\n config.options[c.id]=c.checked;\n }\n if (fn_init) c.fn_init=fn_init.trim().substr(1,fn_init.length-2); // trim off surrounding { and } delimiters\n if (fn_click) c.fn_click=fn_click.trim().substr(1,fn_click.length-2);\n c.onclick(); // compute initial state and save in tiddler/config/cookie\n w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;\n }\n }\n }\n)\n//}}}\n\n//{{{\nfunction onClickCheckbox()\n{\n if (this.fn_init) // custom function hook to set initial state (run only once)\n { try { eval(this.fn_init); this.fn_init=null; } catch(e) { displayMessage("Checkbox init error: "+e.toString()); } }\n else if (this.fn_click) // custom function hook to override or react to changes in checkbox state\n { try { eval(this.fn_click) } catch(e) { displayMessage("Checkbox click error: "+e.toString()); } }\n if (this.id) // save state in config AND cookie (only when ID starts with 'chk')\n { config.options[this.id]=this.checked; saveOptionCookie(this.id); }\n if (!this.id || this.id.substr(0,3)!="chk") { // save state in tiddler content (only if changed)\n var t=store.tiddlers[story.findContainingTiddler(this).id.substr(7)];\n if (this.checked!=(t.text.substr(this.srcpos,1).toUpperCase=="X")) {\n t.text=t.text.substr(0,this.srcpos)+(this.checked?"X":"_")+t.text.substr(this.srcpos+1);\n store.setDirty(true);\n }\n }\n // DEBUG alert("after [id:"+this.id+"]="+this.checked+(this.fn_click?"\snfunction:\sn"+this.fn_click:""));\n return true;\n}\n//}}}\n// //===
! Preferred Method\n# Create new Tiddlers directly in the MainMenu by typing them in the MainMenu Tiddler.\n\n! Method 2\n# Click CreateNewTiddler in the MainMenu.\n# Edit the title and content to create.\n\n! Method 3\n# Enter a mixed-case WikiWord (or double square brackets for NonWikiWordLinks) into an existing Tiddler.\n# Click on the new italicized "empty" Tiddler to edit.\n# When you are done editing, the Tiddler is created.
You can specify your own styles -- that will persist even if you upgrade GTDTW -- in the new special tiddler, StyleSheet.\n\nStyleSheet is pre-populated so you can see how it works. If you want to print to different sizes of paper, or resize the base fonts, or use different fonts, the body style rules are where you'd start. If you are upgrading your version of GTDTW, you'll need to create and populate the StyleSheet for yourself.\n\nStyleSheet suffers from a bug that truncates long entries with many non-alphanumeric characters, so if you try to put the entire set off styles in there, it probably won't work.
[[@Ruby基础]]
Enter Tiddler edit mode and click "delete" \n\nIf you delete a Tiddler that lives in MainMenu or DefaultTiddlers, you'll need to manually remove them from those SpecialTiddlers.\n\nSee also: RenameTiddlers
I found the [[Aardvark Firefox extension|http://www.karmatics.com/aardvark/]] indispensible in developing GTDTiddlyWiki. Browser view-source doesn't work on TiddlyWiki, so I use Aardvark to "see" the page structure.
Because TiddlyWiki is a single HTML file, you've actually already downloaded the entire software just by viewing this site. If you want to be able to SaveChanges, you can save your own TiddlyWiki to your local drive by right clicking on [[this link|#]] and selecting 'Save link as...' or 'Save target as...'. You can choose where to save the file, and what to call it (but keep the .HTML extension).
Try holding down the alt- or shift-key while clicking on a link to a tiddler, on the 'options' button or on the CloseButton for a tiddler. Kind of a respectful homage to Mac OS X, which does something similar for many of its system animations. (On browsers like InternetExplorer that use the shift key to open a new window, it's best to use the alt-key).
You can email the creator of TiddlyWiki at jeremy (at) osmosoft (dot) com.
Edit this tiddler to see how to insert images.\n[img[http://img110.echo.cx/img110/139/gorilla8nw.jpg]]
There's now an option under InterfaceOptions to allow TiddlyWiki's animation effects to be turned off.
''Bold''\n==Strike==\n__Underline__\n//Italic//\n2^^3^^=8\na~~ij~~ = -a~~ji~~\n@@highlight@@\n@@color(green):green colored@@\n@@bgcolor(#ff0000):color(#ffffff):red colored@@
FireFox lets you SaveChanges in TiddlyWiki, but you will see up to three dialogs asking your permission for the local file operations. You must allow all three operations for it to work properly. Note that you can select the //Remember this decision// option to avoid seeing the dialogs in future.
Released in September 2004, the [[first version|firstversion.html]] was pretty basic, weighing in at 52KB.
StyleSheetLayout\nStyleSheetColors\nSideBarTabs\n\n[[internal link(not existing)]]\n[[internal link(exists)|StyleSheet]]\n[[external link|http://www.tiddlywiki.com]]\n[[a pretty link that doesn't exist|blahBlueBlah]]\n\n<<newTiddler>>\n\n!Header 1\n!!Header 2\n!!!Header 3\n!!!!Header 4\n!!!!!Header 5\n\n''Bold''\n==Strike==\n__Underline__\n//Italic//\n2^^3^^=8\na~~ij~~ = -a~~ji~~\n@@highlight@@\n@@color(green):green colored@@\n@@bgcolor(#ff0000):color(#ffffff):red colored@@\n\n[img[Selectutorial|http://css.maxdesign.com.au/selectutorial/images/header.gif][http://css.maxdesign.com.au/selectutorial/]]\n\n{{{\n Preformated text\n}}}\n\nI think this is {{{rendered as code}}}.\n\nTo make quoted bits of text stand out, you can use BlockQuotes within your [[tiddler]]s, like this:\n\nJeremyRuston said:\n<<<\nA TiddlyWiki is like a blog because it's divided up into neat little chunks, but it encourages you to read it by hyperlinking rather than sequentially: if you like, a non-linear blog analogue that binds the individual microcontent items into a cohesive whole.\n<<<\n\nLike BulletPoints and NumberedBulletPoints, you can have three different levels of BlockQuotes. Just [[edit]] this tiddler to see how it's done.\n\n>level 1\n>level 1\n>>level 2\n>>level 2\n>>>level 3\n>>>level 3\n>>level 2\n>level 1\n\nCreating BulletPoints is simple.\n* Just add an asterisk\n* at the beginning of a line.\n** If you want to create sub-bullets\n** start the line with two asterisks\n*** And if you want yet another level\n*** use three asterisks\n* Edit this tiddler to see how it's done\n* You can also do NumberedBulletPoints\n\nIt's easy to create NumberedBulletPoints.\n# Use a single '#' at the start of each line\n# and the tiddler will automatically\n# start numbering your list.\n## If you want a sub-list\n## within any bullets\n## add two '#'s at the start of the lines.\n# When you go back to a single '#'\n# the main numbered list will start up\n# where it left off.\nIt's just as simple to do normal BulletPoints.\n\nEdit this tiddler to see how to insert images.\n[img[Fractal vegetable|fractalveg.jpg]]\n(This curious vegetable is called 'Romanesque broccoli' and is one of [[my photos|http://www.flickr.com/photos/jermy/]])\n\nYou can divide a tiddler into\n----\nsections by typing four dashes on a line by themselves\n\n*sample:\n|!th1111111111|!th2222222222|\n|>| colspan |\n| rowspan |left|\n|~| right|\n|bgcolor(#a0ffa0):colored| center |\n|caption|c\n\n*sample (changed caption and table headers):\n|caption|c\n|th1111111111|th2222222222|h\n|>| colspan |\n| rowspan |left|\n|~| right|\n|bgcolor(#a0ffa0):colored| center |\n\n|Standard Periodic Table (ref. Wikipedia)|c\n|| !1 | !2 |!| !3 | !4 | !5 | !6 | !7 | !8 | !9 | !10 | !11 | !12 | !13 | !14 | !15 | !16 | !17 | !18 |\n|!1|bgcolor(#a0ffa0): @@color(red):H@@ |>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>||bgcolor(#c0ffff): @@color(red):He@@ |\n|!2|bgcolor(#ff6666): Li |bgcolor(#ffdead): Be |>|>|>|>|>|>|>|>|>|>||bgcolor(#cccc99): B |bgcolor(#a0ffa0): C |bgcolor(#a0ffa0): @@color(red):N@@ |bgcolor(#a0ffa0): @@color(red):O@@ |bgcolor(#ffff99): @@color(red):F@@ |bgcolor(#c0ffff): @@color(red):Ne@@ |\n|!3|bgcolor(#ff6666): Na |bgcolor(#ffdead): Mg |>|>|>|>|>|>|>|>|>|>||bgcolor(#cccccc): Al |bgcolor(#cccc99): Si |bgcolor(#a0ffa0): P |bgcolor(#a0ffa0): S |bgcolor(#ffff99): @@color(red):Cl@@ |bgcolor(#c0ffff): @@color(red):Ar@@ |\n|!4|bgcolor(#ff6666): K |bgcolor(#ffdead): Ca ||bgcolor(#ffc0c0): Sc |bgcolor(#ffc0c0): Ti |bgcolor(#ffc0c0): V |bgcolor(#ffc0c0): Cr |bgcolor(#ffc0c0): Mn |bgcolor(#ffc0c0): Fe |bgcolor(#ffc0c0): Co |bgcolor(#ffc0c0): Ni |bgcolor(#ffc0c0): Cu |bgcolor(#ffc0c0): Zn |bgcolor(#cccccc): Ga |bgcolor(#cccc99): Ge |bgcolor(#cccc99): As |bgcolor(#a0ffa0): Se |bgcolor(#ffff99): @@color(green):Br@@ |bgcolor(#c0ffff): @@color(red):Kr@@ |\n|!5|bgcolor(#ff6666): Rb |bgcolor(#ffdead): Sr ||bgcolor(#ffc0c0): Y |bgcolor(#ffc0c0): Zr |bgcolor(#ffc0c0): Nb |bgcolor(#ffc0c0): Mo |bgcolor(#ffc0c0): Tc |bgcolor(#ffc0c0): Ru |bgcolor(#ffc0c0): Rh |bgcolor(#ffc0c0): Pd |bgcolor(#ffc0c0): Ag |bgcolor(#ffc0c0): Cd |bgcolor(#cccccc): In |bgcolor(#cccccc): Sn |bgcolor(#cccc99): Sb |bgcolor(#cccc99): Te |bgcolor(#ffff99): I |bgcolor(#c0ffff): @@color(red):Xe@@ |\n|!6|bgcolor(#ff6666): Cs |bgcolor(#ffdead): Ba |bgcolor(#ffbfff):^^*1^^|bgcolor(#ffc0c0): Lu |bgcolor(#ffc0c0): Hf |bgcolor(#ffc0c0): Ta |bgcolor(#ffc0c0): W |bgcolor(#ffc0c0): Re |bgcolor(#ffc0c0): Os |bgcolor(#ffc0c0): Ir |bgcolor(#ffc0c0): Pt |bgcolor(#ffc0c0): Au |bgcolor(#ffc0c0): @@color(green):Hg@@ |bgcolor(#cccccc): Tl |bgcolor(#cccccc): Pb |bgcolor(#cccccc): Bi |bgcolor(#cccc99): Po |bgcolor(#ffff99): At |bgcolor(#c0ffff): @@color(red):Rn@@ |\n|!7|bgcolor(#ff6666): Fr |bgcolor(#ffdead): Ra |bgcolor(#ff99cc):^^*2^^|bgcolor(#ffc0c0): Lr |bgcolor(#ffc0c0): Rf |bgcolor(#ffc0c0): Db |bgcolor(#ffc0c0): Sq |bgcolor(#ffc0c0): Bh |bgcolor(#ffc0c0): Hs |bgcolor(#ffc0c0): Mt |bgcolor(#ffc0c0): Ds |bgcolor(#ffc0c0): Rg |bgcolor(#ffc0c0): @@color(green):Uub@@ |bgcolor(#cccccc): Uut |bgcolor(#cccccc): Uuq |bgcolor(#cccccc): Uup |bgcolor(#cccccc): Uuh |bgcolor(#fcfecc): @@color(#cccccc):Uus@@ |bgcolor(#ecfefc): @@color(#cccccc):Uuo@@ |\n\n| !Lanthanides^^*1^^|bgcolor(#ffbfff): La |bgcolor(#ffbfff): Ce |bgcolor(#ffbfff): Pr |bgcolor(#ffbfff): Nd |bgcolor(#ffbfff): Pm |bgcolor(#ffbfff): Sm |bgcolor(#ffbfff): Eu |bgcolor(#ffbfff): Gd |bgcolor(#ffbfff): Tb |bgcolor(#ffbfff): Dy |bgcolor(#ffbfff): Ho |bgcolor(#ffbfff): Er |bgcolor(#ffbfff): Tm |bgcolor(#ffbfff): Yb |\n| !Actinides^^*2^^|bgcolor(#ff99cc): Ac |bgcolor(#ff99cc): Th |bgcolor(#ff99cc): Pa |bgcolor(#ff99cc): U |bgcolor(#ff99cc): Np |bgcolor(#ff99cc): Pu |bgcolor(#ff99cc): Am |bgcolor(#ff99cc): Cm |bgcolor(#ff99cc): Bk |bgcolor(#ff99cc): Cf |bgcolor(#ff99cc): Es |bgcolor(#ff99cc): Fm |bgcolor(#ff99cc): Md |bgcolor(#ff99cc): No |\n\n*Chemical Series of the Periodic Table\n**@@bgcolor(#ff6666): Alkali metals@@\n**@@bgcolor(#ffdead): Alkaline earth metals@@\n**@@bgcolor(#ffbfff): Lanthanides@@\n**@@bgcolor(#ff99cc): Actinides@@\n**@@bgcolor(#ffc0c0): Transition metals@@\n**@@bgcolor(#cccccc): Poor metals@@\n**@@bgcolor(#cccc99): Metalloids@@\n**@@bgcolor(#a0ffa0): Nonmetals@@\n**@@bgcolor(#ffff99): Halogens@@\n**@@bgcolor(#c0ffff): Noble gases@@\n\n*State at standard temperature and pressure\n**those in @@color(red):red@@ are gases\n**those in @@color(green):green@@ are liquids\n**those in black are solids
TiddlyWiki uses Wiki style markup, a way of lightly "tagging" plain text so it can be transformed into HTML. Edit this Tiddler to see samples.\n\n! Header Samples\n!Header 1\n!!Header 2\n!!!Header 3\n!!!!Header 4\n!!!!!Header 5\n\n! Unordered Lists:\n* Lists are where it's at\n* Just use an asterisk and you're set\n** To nest lists just add more asterisks...\n***...like this\n* The circle makes a great bullet because once you've printed a list you can mark off completed items\n* You can also nest mixed list types\n## Like this\n\n! Ordered Lists\n# Ordered lists are pretty neat too\n# If you're handy with HTML and CSS you could customize the [[numbering scheme|http://www.w3schools.com/css/pr_list-style-type.asp]]\n## To nest, just add more octothorpes (pound signs)...\n### Like this\n* You can also\n** Mix list types\n*** like this\n# Pretty neat don't you think?\n\n! Tiddler links\nTo create a Tiddler link, just use mixed-case WikiWord, or use [[brackets]] for NonWikiWordLinks. This is how the GTD style [[@Action]] lists are created. \n\nNote that existing Tiddlers are in bold and empty Tiddlers are in italics. See CreatingTiddlers for details.\n\n! External Links\nYou can link to [[external sites|http://google.com]] with brackets. You can also LinkToFolders on your machine or network shares.\n\n! Images\nEdit this tiddler to see how it's done.\n[img[http://img110.echo.cx/img110/139/gorilla8nw.jpg]]\n\n!Tables\n|!th1111111111|!th2222222222|\n|>| colspan |\n| rowspan |left|\n|~| right|\n|colored| center |\n|caption|c\n\nFor a complex table example, see PeriodicTable.\n\n! Horizontal Rules\nYou can divide a tiddler into\n----\nsections by typing four dashes on a line by themselves.\n\n! Blockquotes\n<<<\nThis is how you do an extended, wrapped blockquote so you don't have to put angle quotes on every line.\n<<<\n>level 1\n>level 1\n>>level 2\n>>level 2\n>>>level 3\n>>>level 3\n>>level 2\n>level 1\n\n! Other Formatting\n''Bold''\n==Strike==\n__Underline__\n//Italic//\nSuperscript: 2^^3^^=8\nSubscript: a~~ij~~ = -a~~ji~~\n@@highlight@@\n@@color(green):green colored@@\n@@bgcolor(#ff0000):color(#ffffff):red colored@@\n
[[Forum for discussion of GTDTW|http://shared.snapgrid.com/gtd-forum/]]. Supercedes the GoogleGroup. Anyone can read posts, but a simple registration is required for posting (privacy guaranteed).
See [[About GTD TiddlyWiki]].
Getting Things Done is a simple and effective personal productivity method by David Allen. You can [[get the book from Amazon|http://www.amazon.com/exec/obidos/tg/detail/-/0142000280/qid=1115360158/sr=8-1/ref=pd_csp_1/002-8782437-3718417?v=glance&s=books&n=507846]].\n\nAlso check out the GTD community at the 43Folders [[website|http://www.43folders.com/]], [[wiki|http://wiki.43folders.com/index.php/Main_Page]], and [[newsgroup|http://groups-beta.google.com/group/43Folders/]].\n\n----\n"Getting Things Done" is © David Allen at [[Davidco|http://davidco.com]]. Davidco has no affiliation with TiddlyWiki or GTDTiddlyWiki.
/***\n!GTD Style\n\n!Generic rules /%==================================================================== %/\n***/\n/*{{{*/\nbody {\n background: #464646 url('http://shared.snapgrid.com/images/tiddlywiki/bodygradient.png') repeat-x top fixed;\n color: #000;\n font: .82em/1.25em "Bitstream Vera Sans", Verdana, Helvetica, Arial, sans-serif;\n/*"Lucida Sans Unicode", "Lucida Grande","Trebuchet MS", */\n}\n/*}}}*/\n/***\n!Header rules /%====================================================================== %/\n***/\n/*{{{*/\n#contentWrapper\n{\n margin: 0 auto;\nwidth: 59em;\nposition: relative;\n}\n\n#header\n{\n color: #fff;\n padding: 1.5em 1em .6em 0;\n}\n\n#siteTitle {\n\n font-size: 2.3em;\n margin: 0;\n}\n\n#siteSubtitle {\n font-size: 1em;\n padding-left: .8em;;\n}\n\n#titleLine{\n background: transparent;\n padding: 0;\n}\n\n#titleLine a {\n color: #cf6;\n}\n/*}}}*/\n/***\n!Sidebar rules /%====================================================================== %/\n***/\n/*{{{*/\n#sidebar{\n left: 0;\nwidth: 18em;\n margin: .9em .9em 0 0;\n color: #000;\n background: transparent;\n}\n/*}}}*/\n/***\n!Main menu rules /%=================================================================== %/\n***/\n/*{{{*/\n#mainMenu{\n position: static;\n width: auto;\n\n background: #600;\n border-right: 3px solid #500;\npadding: 0;\n text-align: left;\n font-size: 1em;\n}\n\n#mainMenu ul{\n padding: 0;\n margin: 0;\n list-style: none;\n}\n\n#mainMenu li a,\n#mainMenu li a.button{\n display: block;\n padding: 0 5px 0 10px;\n border-bottom: 1px solid #500;\n border-top: 1px solid #900;\nmargin: 0;\n}\n\n#mainMenu a,\n#mainMenu a.button{\n height: 22px;\nheight: 1.83em;\n line-height: 22px;\n color: #fff;\n background: #700;\nmargin-left: 1em;\n}\n\n#mainMenu a:hover,\n#mainMenu a.button:hover {\n background: #b00;\n color: #fff;\n}\n/*}}}*/\n/***\n!Sidebar options rules /%============================================================ %/\n***/\n/*{{{*/\n#sidebarOptions {\n background: #eeb;\n border-right: 3px solid #bb8;\n color: #B4C675;\n padding: .5em 0;\n}\n\n#sidebarOptions a {\n color: #700;\n margin: .2em .8em;\n padding: 0;\n}\n\n#sidebarOptions a:hover, #sidebarOptions a:active {\n color: #fff;\n background: #700;\n}\n\n#sidebarOptions input{\n margin: 2px 10px;\n border: 1px inset #333;\npadding: 0;\n}\n\n#sidebarOptions .sliderPanel {\n background: #fff;\n color: #000;\n padding: 5px 10px;\n font-size: .9em;\n}\n\n#sidebarOptions .sliderPanel a{\n font-weight: normal;\n margin: 0;\n}\n\n#sidebarOptions .sliderPanel a:link,#sidebarOptions .sliderPanel a:visited {\n color: #700;\n}\n\n#sidebarOptions .sliderPanel a:hover,#sidebarOptions .sliderPanel a:active {\n color: #fff;\n background: #700;\n}\n/*}}}*/\n/***\n!Sidebar tabs rules /%===================================================================== %/\n***/\n/*{{{*/\n#sidebarTabs {\n background: transparent;\n border-right: 3px solid #740;\n border-bottom: 3px solid #520;\n border: 0;\n padding: 0;\n}\n\n#contentWrapper #sidebarTabs a,\n#contentWrapper #displayArea .tabContents a{\n color: #fff;\n}\n\n#contentWrapper #sidebarTabs a:hover,\n#contentWrapper #displayArea .tabContents a:hover {\n background: #000;\n color: #fff;\n}\n\n#contentWrapper #sidebarTabs a:active,\n#contentWrapper #displayArea .tabContents a:active{\n color: #000;\n}\n\n\n\n#contentWrapper .tabSelected {\n background: #960;\n}\n\n#contentWrapper .tabUnselected{\n background: #660;\n}\n\n#contentWrapper #sidebar .tabset{\n background: #eeb;\n border-right: 3px solid #bb8;\n padding: 0 0 0 .75em;\n}\n\n#contentWrapper .tabContents{\nfont-size: .95em;\nbackground: #960;\n border-right: 3px solid #740;\n border-bottom: 3px solid #520;\n padding: .75em;\n}\n\n#contentWrapper .tabContents{\n width: auto;\n}\n\n#contentWrapper #sidebarTabs .tabContents .tabset,\n#contentWrapper .tabContents .tabset{\n border: 0;\n padding: 0;\n background: transparent;\n}\n\n#contentWrapper .tabContents .tabSelected,\n#contentWrapper .tabContents .tabContents {\n background: #700;\n border: 0;\n}\n\n#contentWrapper .tabContents .tabUnselected {\n background: #440;\n}\n\n#contentWrapper .tabset a {\n color: #fff;\n padding: .2em .7em;\n margin: 0 .17em 0 0;\n height: 2em;\nposition: static;\n}\n\n#contentWrapper .tabset a:hover {\n background: #000;\n color: #fff;\n}\n\n#contentWrapper .tabset a:active {\n color: #000;\n}\n\n#contentWrapper .tabContents ul{\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n#contentWrapper .tabContents .tabContents ul{\n color: #eeb;\n}\n\n.tabContents ul a,\n.tabContents ul .button{\n color: #fff;\n display: block;\n padding: .1em 0 .1em .7em;\n background: transparent;\n border: 0;\n}\n\n.tabContents ul a:hover {\n color: #fff;\n background: #000;\n}\n/*}}}*/\n/***\n!License panel rules /%==================================================================== %/\n***/\n/*{{{*/\n#licensePanel {\n padding: 0px 1em;\n font-size: .9em;\n}\n\n#licensePanel a {\n color: #960;\n display: block;\n margin-top: .9em;\n}\n\n#licensePanel a:hover {\n color: #fff;\n background: transparent;\n}\n/*}}}*/\n/***\n!Popup rules /%================================================================= %/\n***/\n/*{{{*/\n.popup {\n font-size: .8em;\n padding: 0em;\n background: #333;\n border: 1px solid #000;\n}\n\n.popup hr {\n margin: 1px 0 0 0;\n visibility: hidden;\n}\n\n.popup li.disabled {\n color: #666;\n}\n\n.popup li a,\n.popup li a:visited{\n color: #000;\n border: .1em outset #cf6;\n background: #cf6;\n}\n\n.popup li a:hover {\n background: #ef9;\n color: #000;\n}\n/*}}}*/\n/***\n!Tiddler display rules /%================================================================= %/\n***/\n/*{{{*/\n#messageArea{\n font-size: .9em;\n padding: .4em;\n background: #FFE72F;\n border-right: .25em solid #da1;\n border-bottom: .25em solid #a80;\n text-align: center;\n position: fixed;\n top: 10px;\n right: 10px;\n color: #000;\n}\n\n#contentWrapper #messageArea a{\n color: #00e;\n text-decoration: none;\n}\n/*}}}*/\n/***\n!Tiddler display rules /%================================================================== %/\n***/\n/*{{{*/\n#displayArea {\n width: 39.75em;\n margin: 0 0 0 17em;\n}\n\n.tiddler {\n margin: 0 0 .9em 0;\n padding: 0 1em;\n border-right: .25em solid #aaa;\n border-bottom: .25em solid #555;\n background: #fff;\n}\n\n.title {\n font-size: 1.5em;\n font-weight: bold;\n color: #900;\n}\n\n.toolbar {\n font-size: .8em;\n padding: .5em 0;\n}\n\n.toolbar .button{\n padding: .1em .3em;\n color: #000;\n\n border: .1em outset #cf6;\n background: #cf6;\nmargin: .1em;\n}\n\n.toolbar .button:hover {\n background: #ef9;\n color: #000;\n}\n\n.toolbar .button:active {\n background: #ff0;\n}\n\n/*}}}*/\n/***\n!Viewer rules /% ------------------------------------------------------------------------------------------ %/\n***/\n/*{{{*/\n.viewer {\n line-height: 1.4em;\n font-size: 1em;\n}\n\n.viewer a:link, .viewer a:visited {\n color: #15b;\n}\n\n.viewer a:hover {\n color: #fff;\n background: #000;\n}\n\n.viewer .button{\n background: transparent;\n border-top: 1px solid #eee;\n border-left: 1px solid #eee;\n}\n\n.viewer .button:hover{\n background: #eee;\n color: #000;\n}\n\n.viewer .button:active{\n background: #ccc;\n border-bottom: 1px solid #eee;\n border-right: 1px solid #eee;\n border-top: 1px solid #111;\n border-left: 1px solid #111;\n}\n\n\n.viewer blockquote {\n border-left: 3px solid #777;\n margin: .3em;\n padding: .3em;\n}\n\n.viewer pre{\n background: #fefefe;\n border: 1px solid #f1f1f1;\n}\n\n.viewer pre, .viewer code{\n color: #000;\n}\n\n.viewer ul {\n padding-left: 30px;\n}\n\n.viewer ol {\n padding-left: 30px;\n}\nul{\nlist-style-type: asquare;\n}\nol{ \n list-style-type: decimal;\n}\n\nol ol{ \n list-style-type: lower-alpha;\n}\n\nol ol ol{ \n list-style-type: lower-roman;\n}\n\n.viewer ul, .viewer ol, .viewer p {\n margin: .0;\n}\n\n.viewer li {\n margin: .2em 0;\n}\n\nh1,h2,h3,h4,h5,h6 {\n font-weight: bold;\n background: #eee;\n padding: 2px 10px;\n margin: 5px 0;\n}\n\n.viewer h1 {font-size: 1.3em;}\n.viewer h2 {font-size: 1.2em;}\n.viewer h3 {font-size: 1.1em;}\n.viewer h4 {font-size: 1em;}\n.viewer h5 { font-size: .9em;}\n.viewer h6 { font-size: .8em;}\n\n.viewer table {\n border: 2px solid #303030;\n font-size: 11px;\n margin: 10px 0;\n}\n\n.viewer th, .viewer thead td{\n color: #000;\n background: #eee;\n border: 1px solid #aaa;\n padding: 0 3px;\n}\n\n.viewer td {\n border: 1px solid #aaa;\n padding: 0 3px;\n}\n\n.viewer caption {\n padding: 3px;\n}\n\n.viewer hr {\n border: none;\n border-top: dotted 1px #777;\n height: 1px;\n color: #777;\n margin: 7px 0;\n}\n\n.viewer\n{\n margin: .5em 0 0 0;\n padding: .5em 0;\n border-top: 1px solid #ccc;\n}\n\n.highlight {\n color: #000;\n background: #ffe72f;\n}\n/*}}}*/\n/***\n!Editor rules /% ----------------------------------------------------------------------------------------- %/\n***/\n/*{{{*/\n.editor {\n font-size: .8em;\n color: #402C74;\n padding: .3em 0;\n}\n\n.editor input, .editor textarea {\n font: 1.1em/130% "Andale Mono", "Monaco", "Lucida Console", "Courier New", monospace;\n margin: 0;\n border: 1px inset #333;\n padding: 2px 0;\n}\n\n.editor textarea {\n height: 42em;\n width: 100%;\n}\n\ninput:focus, textarea:focus\n{\n background: #ffe;\n border: 1px solid #000;\n}\n.footer\n{\n padding: .5em 0;\n margin: .5em 0;\n border-top: 1px solid #ddd;\n color: #555;\n text-align: center; \n}\n/*}}}*/\n/***\n!IE Display hacks /% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%/\n***/\n/*{{{*/\nbody{\n _text-align: center;\n}\n\n#contentWrapper\n{\n/* _width: 770px; CSS UNDERSCORE HACK FOR PROPER WIN/IE DISPLAY */\n _text-align: left; /* CSS UNDERSCORE HACK FOR PROPER WIN/IE DISPLAY */ \n}\n\n#messageArea{\n _position: absolute;\n}\n/*}}}*/
The [[Google Group|http://groups-beta.google.com/group/GTD-TiddlyWiki?hl=en]] has been superceded by the GTDTWForum
Edit this to see how to create Headers\n\n!Header 1\n!!Header 2\n!!!Header 3\n!!!!Header 4\n!!!!!Header 5\n
Welcome to the GTDTiddlyWiki, an experimental MicroContent WikiWikiWeb originally built by JeremyRuston and adapted for GTD use by NathanBowers. It's written in HTML, CSS and JavaScript to run on any modern browser without needing any ServerSide logic. It allows anyone to create personal SelfContained hypertext documents that can be posted to any web server, sent by email or kept on a USB thumb drive to make a WikiOnAStick.
AKA: "Personal Analog Assistant"\n\nA fun term for running your GTD lists from index cards. See [[43Folders|http://merlin.blogs.com/43folders/2004/09/introducing_the.html]] for the full rundown (be sure to check the trackbacks. Also check out [[Adam Gurno's|http://gurno.com/adam/j2/index.php?p=44]] ideas for printing your own special cards.
When GTDTiddlyWiki is updated with enhancements and fixes, here's how to upgrade while keeping your data.\n\n* Just to be safe, create a backup of your current file and archive it somewhere.\n\nOkay then:\n* Open your TiddlyWiki file (say it's called "mystuff.html") in a browser.\n* Without closing that page, right-click on [[this link|#]], select 'Save target' or 'Save link' and save it as "mystuff.html", replacing your existing file\n* Now go back to the previously opened copy of "mystuff.html" in your browser and click "save changes" in the sidebar.\n* Refresh the page in the browser to verify that the upgrade has worked
*sample:\n|!th1111111111|!th2222222222|\n|>| colspan |\n| rowspan |left|\n|~| right|\n|bgcolor(#a0ffa0):colored| center |\n|caption|c\n*another sample: see PeriodicTable.\n
When you type more than three characters in the search box at the upper right, any matching tiddlers are automatically displayed with the text highlighted. There's a couple of minor issues: the highlights don't get removed when you clear the search, and occasionally, on some browsers, keystrokes get missed if you type quickly so you may need to click the 'search' button to manually trigger the search.
InterfaceOptions are displayed when you click the 'options' button on the right. They are saved in a cookie on your browser, making them sticky between visits. RegExpSearch allows more complex search expressions; CaseSensitiveSearch does as it's name implies. The user name for edits should be set //before// starting to edit things (ouch. another bug).
InternetExplorer on Windows allows you to SaveChanges in TiddlyWiki. It will give you an ActiveX warning, and ask for your permission to proceed each time. It should work from version 4, but I have only extensively tested against version 6. I have found some annoying difficulties with XpServicePack2, but there's always FireFox.
The creator of TiddlyWiki and a technologist based in London. He does consultancy work through his company [[Osmosoft|http://www.osmosoft.com]], as well as pursuing some independent projects like TiddlyWiki.
* All your action lists live in one HTML file, ideal for portability and simplicity.\n* [[Print3x5]] cards for your HipsterPDA right from your browser.\n* Runs locally, no network connection needed.\n* User defined CustomStyleSheet\n* Built with HTML, CSS, and Javascript, so it's easy to modify.\n* Really good incremental and regular expression search.\n* Your updates are date and name stamped (hover over the Timeline entries).\n* Your most recent version is automatically backed up when you SaveChanges (You can edit the Javascript to do incremental time-stamped backups. See the RevisionHistory for details).\n* Presumably, TiddlyWiki could run on a capable handheld device, but this is untested.
* Double click on a Tidder entry to edit it.\n* [Control + Enter] accepts your changes and switches out of editing mode\n* [Escape] abandons your changes and reverts the tiddler to it's previous state
!Bugs\n* ==StyleSheet suffers from a bug that truncates long entries with many non-alphanumeric characters, so if you try to put the entire set of styles in there, it probably won't work.==\n* =="Highlighted" and Hexidecimal colored text formatting is broken==\n* When printing WIN/IE 6 inserts one blank page because it does not recognize the :first-child CSS psuedo element.\n* ==WIN/IE 6 messes up list items when you edit a Tiddler with multiple headings.==\n\n!Annoyances\n* You have to do alot to customize your browser print settings to remove the page URL, pagination, timestamp, and ensure that the output is sized and paged correctly.\n* Firefox/Mac has no "page properties" interface for removing the page URL, page numbers, etc... from printed pages. This is pretty lame. Try entering about:config in Firefox's URL bar and look for "print" to configure it the hard way. Ask the Firefox development team to fix this.\n\n!Help out\n* If you you encounter new bugs, can help fix bugs, or can help make this usable in other browsers, or handhelds, go to the GTDTWForum. Thanks!
The format for PrettyLinks allows for links that open local or network folders. Depending on your browser and operating system, the folders are opened in Windows Explorer, the OS X Finder, or the browser itself.\n\nEdit this tiddler to see [[this link to a Windows network share|file://server/share/folder/path/name]], [[this link to a Windows drive-mapped folder|file:///c:/folder/path/name]] and [[this link to a Unix-style folder|file:///folder/path/name]].
*[[@Ruby基础]]\n*[[@Ruby配置/设定]]\n*[[@Ruby进阶]]\n*[[@Rbuy类库参考]]\n*[[@附录]]\n*[[@Misc]]\n*[[@正则表达式语法]]\n\n*FormattingInstructions\n*DefaultTiddlers\n*<<newTiddler>>\n*MainMenu
MicroContent being a fashionable word for self-contained fragments of content that are typically smaller than entire pages. Often MicroContent is presented via some kind of aggregation that reduces the perceptual shock and resource cost of context switching (eg Blogs aggregating several entries onto a page or Flickr presenting photos in an album). This TiddlyWiki aggregates MicroContent items that I call 'tiddlers' into pages that are loaded in one gulp and progressively displayed as the user clicks hypertext links to read them.
Nathan is a web developer based in Los Angeles. His website is [[Snapgrid.com|http://snapgrid.com]]. Have questions, comments, or suggestions? Visit the GTDTWForum.
This ThirdVersion of TiddlyWiki adds:\n* the ability to easily SaveChanges on FireFox and InternetExplorer\n* a new liquid CSS layout that fills the width of the browser window\n* InterfaceOptions revealed by clicking the new 'options' button on the right\n* some BugFixes\n* KeyboardShortcuts so you can finish editing a tiddler with Control-Enter or abandon it with Escape\n* a more flexible OpenSourceLicense\n* a bunch of features from IsaoSonobe's [[adaptation|http://www-gauge.scphys.kyoto-u.ac.jp/~sonobe/OgreKit/OgreKitWiki.html]] of TiddlyWiki including ExtendedFormatting, NonWikiWordLinks, PrettyLinks, [[Headings]], BulletPoints, NumberedLists, HtmlTables, BlockQuotes, HorizontalRules and...\n* ...EmbeddedImages:\n[img[http://img110.echo.cx/img110/139/gorilla8nw.jpg]]
TiddlyWiki is a spare time project that I'm making available under an OpenSourceLicense. Accordingly, there's no warranty on it, and you can only use it at your own risk. To report bugs go to the GTDTWForum.
To make a tiddler that doesn't have a WikiWord as it's name, you can enclose the name in [[double square brackets]] - edit this tiddler to see an example. After saving the tiddler you can then click on the link to create the new tiddler. NonWikiWordLinks permits tiddlers to be created with names that are made from character sets that don't have upper and lower case.
start\n#item1\n#item2\n##item2.1\n##item2.2\n##item2.3\n#item3\n##item3.1\n###item3.1.1\n###item3.1.2\n\nend
TiddlyWiki is published under a BSD OpenSourceLicense that gives you the freedom to use it pretty much however you want, including for commercial purposes, as long as you keep my copyright notice. I'd appreciate a link back to http://www.tiddlywiki.com as well.
! Open Projects\n* Complete TPS reports\n* Ensure y2k compliance\n* Maintain quiet dignity\n\n! Done\n* Plan TPS project
<div id='header'>\n<div id='titleLine'>\n<span id='siteTitle' refresh='content' tiddler='SiteTitle'></span>\n<span id='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='sidebar'>\n<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div><div id="licensePanel">\n<a rel="license" href="http://shared.snapgrid.com/gtd_tiddlywiki.html#RevisionHistory" target="_new">GTDTW Version <span macro="version"></span></a>\n<a rel="license" href="http://www.tiddlywiki.com" target="_new">\nTiddlyWiki is published by Jeremy Ruston at Osmosoft under a BSD open source license</a>\n<a rel="license" href="http://snapgrid.com" target="_new">GTD TiddlyWiki is a modification by Nathan Bowers at Snapgrid under the same license terms.</a>\n<a rel="license" href="http://davidco.com" target="_new">"Getting Things Done" is © David Allen at Davidco. Davidco has no affiliation with TiddlyWiki or GTD TiddlyWiki.</a></div></div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>
|Standard Periodic Table (ref. Wikipedia)|c\n|| !1 | !2 |!| !3 | !4 | !5 | !6 | !7 | !8 | !9 | !10 | !11 | !12 | !13 | !14 | !15 | !16 | !17 | !18 |\n|!1|bgcolor(#a0ffa0): @@color(red):H@@ |>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>||bgcolor(#c0ffff): @@color(red):He@@ |\n|!2|bgcolor(#ff6666): Li |bgcolor(#ffdead): Be |>|>|>|>|>|>|>|>|>|>||bgcolor(#cccc99): B |bgcolor(#a0ffa0): C |bgcolor(#a0ffa0): @@color(red):N@@ |bgcolor(#a0ffa0): @@color(red):O@@ |bgcolor(#ffff99): @@color(red):F@@ |bgcolor(#c0ffff): @@color(red):Ne@@ |\n|!3|bgcolor(#ff6666): Na |bgcolor(#ffdead): Mg |>|>|>|>|>|>|>|>|>|>||bgcolor(#cccccc): Al |bgcolor(#cccc99): Si |bgcolor(#a0ffa0): P |bgcolor(#a0ffa0): S |bgcolor(#ffff99): @@color(red):Cl@@ |bgcolor(#c0ffff): @@color(red):Ar@@ |\n|!4|bgcolor(#ff6666): K |bgcolor(#ffdead): Ca ||bgcolor(#ffc0c0): Sc |bgcolor(#ffc0c0): Ti |bgcolor(#ffc0c0): V |bgcolor(#ffc0c0): Cr |bgcolor(#ffc0c0): Mn |bgcolor(#ffc0c0): Fe |bgcolor(#ffc0c0): Co |bgcolor(#ffc0c0): Ni |bgcolor(#ffc0c0): Cu |bgcolor(#ffc0c0): Zn |bgcolor(#cccccc): Ga |bgcolor(#cccc99): Ge |bgcolor(#cccc99): As |bgcolor(#a0ffa0): Se |bgcolor(#ffff99): @@color(green):Br@@ |bgcolor(#c0ffff): @@color(red):Kr@@ |\n|!5|bgcolor(#ff6666): Rb |bgcolor(#ffdead): Sr ||bgcolor(#ffc0c0): Y |bgcolor(#ffc0c0): Zr |bgcolor(#ffc0c0): Nb |bgcolor(#ffc0c0): Mo |bgcolor(#ffc0c0): Tc |bgcolor(#ffc0c0): Ru |bgcolor(#ffc0c0): Rh |bgcolor(#ffc0c0): Pd |bgcolor(#ffc0c0): Ag |bgcolor(#ffc0c0): Cd |bgcolor(#cccccc): In |bgcolor(#cccccc): Sn |bgcolor(#cccc99): Sb |bgcolor(#cccc99): Te |bgcolor(#ffff99): I |bgcolor(#c0ffff): @@color(red):Xe@@ |\n|!6|bgcolor(#ff6666): Cs |bgcolor(#ffdead): Ba |bgcolor(#ffbfff):^^*1^^|bgcolor(#ffc0c0): Lu |bgcolor(#ffc0c0): Hf |bgcolor(#ffc0c0): Ta |bgcolor(#ffc0c0): W |bgcolor(#ffc0c0): Re |bgcolor(#ffc0c0): Os |bgcolor(#ffc0c0): Ir |bgcolor(#ffc0c0): Pt |bgcolor(#ffc0c0): Au |bgcolor(#ffc0c0): @@color(green):Hg@@ |bgcolor(#cccccc): Tl |bgcolor(#cccccc): Pb |bgcolor(#cccccc): Bi |bgcolor(#cccc99): Po |bgcolor(#ffff99): At |bgcolor(#c0ffff): @@color(red):Rn@@ |\n|!7|bgcolor(#ff6666): Fr |bgcolor(#ffdead): Ra |bgcolor(#ff99cc):^^*2^^|bgcolor(#ffc0c0): Lr |bgcolor(#ffc0c0): Rf |bgcolor(#ffc0c0): Db |bgcolor(#ffc0c0): Sq |bgcolor(#ffc0c0): Bh |bgcolor(#ffc0c0): Hs |bgcolor(#ffc0c0): Mt |bgcolor(#ffc0c0): Ds |bgcolor(#ffc0c0): Rg |bgcolor(#ffc0c0): @@color(green):Uub@@ |bgcolor(#cccccc): Uut |bgcolor(#cccccc): Uuq |bgcolor(#cccccc): Uup |bgcolor(#cccccc): Uuh |bgcolor(#fcfecc): @@color(#cccccc):Uus@@ |bgcolor(#ecfefc): @@color(#cccccc):Uuo@@ |\n\n| !Lanthanides^^*1^^|bgcolor(#ffbfff): La |bgcolor(#ffbfff): Ce |bgcolor(#ffbfff): Pr |bgcolor(#ffbfff): Nd |bgcolor(#ffbfff): Pm |bgcolor(#ffbfff): Sm |bgcolor(#ffbfff): Eu |bgcolor(#ffbfff): Gd |bgcolor(#ffbfff): Tb |bgcolor(#ffbfff): Dy |bgcolor(#ffbfff): Ho |bgcolor(#ffbfff): Er |bgcolor(#ffbfff): Tm |bgcolor(#ffbfff): Yb |\n| !Actinides^^*2^^|bgcolor(#ff99cc): Ac |bgcolor(#ff99cc): Th |bgcolor(#ff99cc): Pa |bgcolor(#ff99cc): U |bgcolor(#ff99cc): Np |bgcolor(#ff99cc): Pu |bgcolor(#ff99cc): Am |bgcolor(#ff99cc): Cm |bgcolor(#ff99cc): Bk |bgcolor(#ff99cc): Cf |bgcolor(#ff99cc): Es |bgcolor(#ff99cc): Fm |bgcolor(#ff99cc): Md |bgcolor(#ff99cc): No |\n\n*Chemical Series of the Periodic Table\n**@@bgcolor(#ff6666): Alkali metals@@\n**@@bgcolor(#ffdead): Alkaline earth metals@@\n**@@bgcolor(#ffbfff): Lanthanides@@\n**@@bgcolor(#ff99cc): Actinides@@\n**@@bgcolor(#ffc0c0): Transition metals@@\n**@@bgcolor(#cccccc): Poor metals@@\n**@@bgcolor(#cccc99): Metalloids@@\n**@@bgcolor(#a0ffa0): Nonmetals@@\n**@@bgcolor(#ffff99): Halogens@@\n**@@bgcolor(#c0ffff): Noble gases@@\n\n*State at standard temperature and pressure\n**those in @@color(red):red@@ are gases\n**those in @@color(green):green@@ are liquids\n**those in black are solids
I think this feature from the SecondVersion of TiddlyWiki is quite original. It's a button in the right-hand sidebar that sets the browser address bar to a URL embodying all the currently open tiddlers in the order that they are currently shown. To use it, arrange the open tiddlers that you want, click the permaview button, copy the URL from the browser address bar, and then paste it into an email, web page or whatever.
You can now link to [[external sites|http://www.osmosoft.com]] with ordinary words, without the messiness of the full URL appearing. Edit this tiddler to see how.\n\nYou can also LinkToFolders.
The GTD Tiddly Wiki has been designed to print "HipsterPDA" 3x5 index cards. All you have to do is use your browser's "Print" button or shortcut key.\n\n!Print Features:\n* Print directly to 3x5 from your browser. There is no "printer friendly" link.\n* Pagination: Each Tiddler (or GTD list) will print on it's own sheet. You could have all your lists open and print them all at once.\n* If you know any CSS, you can completely customize the print output.\n* List bullets are circles to help you mark off completed tasks in your HipsterPDA.\n\n[img[http://img15.echo.cx/img15/57/lists2jb.jpg]]\n\n!How to customize print style, typeface, or font size:\n* Edit the StyleSheet Tiddler (it helps to know a little CSS).\n\n!KnownBugs with print:\n* Firefox/Mac has no "page properties" interface for removing the page URL, page numbers, etc... from printed pages. This is pretty lame. Try entering about:config in Firefox's URL bar and look for "print" to configure it the hard way.\n* WIN/IE 6 inserts one blank page because it does not recognize the :first-child CSS psuedo element.\n* You'll probably need to tweak your browser print settings to remove the page URL, pagination, timestamp, and ensure that the output is sized and paged correctly.\n* Your mileage may vary because of platform, font, browser, and printer differences. If you find something that's broken or needs help, visit the GTDTWForum.
The rules governing where a tiddler is displayed sound complicated written down. When you click on a tiddler link within another tiddler, the new one is opened immediately below the current one. If the target tiddler is already open, TiddlyWiki just uses SmoothScrolling to bring it into view. More or less the same thing happens when clicking on a tiddler link within the menu or sidebar, except that the tiddler opens at the top of the page if it is not already open.
RegExpSearch uses JavaScript's [[RegExp syntax|http://www.programmershelp.co.uk/docs/javascript/regexp.html#1193188]] to allow flexible searches.
If you rename a Tiddler and it lives in MainMenu or DefaultTiddlers, you'll need to update those SpecialTiddlers manually.
It's easy to make your own TiddlyWiki that you can publish yourself - see how to SaveChanges for details. If you want to change the layout or the colour scheme, you'll need some basic HTML and CSS knowledge.
GTDTiddlyWiki will incorporate [[updates|http://www.osmosoft.com/#RevisionHistory]] from the official TiddlyWiki and other contributors as appropriate. If you'd like to contribute to development, go the GTDTWForum.\n\nTo see my changes to Javascript, search the source code for "Nathan Edit".\n\nHowToUpgrade | UpdateNotification | VersionArchive\n\n! version 1.0.6 September 3rd 2005\n# Full rebuild based on TiddlyWiki Revision 1.2.32.\n\n! version 1.0.5 May 21st 2005\n# Added version number to footer and VersionArchive (major update soon).\n\n! version 1.0.4 May 17th 2005\n# Added JeremyRuston's CustomStyleSheet feature.\n\n! version 1.0.3 May 17th 2005\n# Now works in Safari (requires [[plugin by Jonathan Paisley|http://www.accela.net/~dankna/tiddlywiki/]]) Thanks Jonathan! \n# Constrained printed images to fit 3x5 cards (this won't work in IE)\n# Added saving on delete and put a small "save" link back into the sidebar.\n# Added links to GTDTWForum and RSS UpdateNotification\n\n! version 1.0.2 May 13th 2005\n# When "done" button or CRTL+ENTER is pressed to make changes to a Tiddler, entire wiki is saved and a backup is created. This should prevent accidental data loss. (Thanks to Ron, Jamie, and Terminus in the [[group|http://groups-beta.google.com/group/GTD-TiddlyWiki/browse_frm/thread/809f958426038e94?hl=en]])\n# Removed "Save Successful" confirmation dialog.\n# Removed big happy "Save" button (and died a little inside) ;) to avoid user ambiguity about saving. Also removed [alt+s] save.\n# Added Camino compatability ([[Thanks Schlafer|http://tinyurl.com/aeqpt]])\n# Added DevelopmentTips\n\n! version 1.0.1 May 10th 2005\n# Added TiddlyWiki fixes from original version 1.2.6\n\n! version 1.0.0 May 9th, 2005\n# Added print style sheet\n# Overhaul of CSS layout\n# Added alt + s quicksave with a simple accesskey attribute.\n# Changed sidebar "Timeline" and "All" to remove BR tags and extra Spaces. Check the javascript functions refreshTabTimeline() and refreshTabAll()\n# Changed incremental date stamped "backup on save" to a single backup file. See the saveChanges() javscript function in this page's source to re-enable datestamped backup.
! Ruby 和 C++ 、 Java的比较\n\n这值得我们再花一些时间来比较一下Ruby,C++,JAVA中的迭代器。在Ruby中,迭代器是一个简单的方法,每当它产生一个新值,都会调用yield方法。使用迭代器只需要给这个迭代器传递一个块,不需要像C++,Java中那样创建辅助类来处理迭代器的状态。从这一点和其它一些特点来说,Ruby是一种透明语言,当你写程序的时候,你只需关注于让功能能够实现,而不必编写脚手架来支持语言的一些功能。\n\n迭代器不仅仅用在数组和哈希等集合结构上,它也能返回上面Fibonacci 例子中那样的序列值,Ruby中的输入输出类也用到了迭代器,这些类实现了迭代器接口,每次返回一个I/O流的下一行。 \n\n<<<\nf = File.open("testfile")\nf.each do |line|\n print line\nend\nf.close\n<<< \nproduces: This is line one\nThis is line two\nThis is line three\nAnd so on... \n\n让我们再看看另外一个迭代器实现。Smalltalk也支持迭代器,如果你用smalltalk语言来计算一个数组中元素的和,可以这样:\n\n<<<\nsumOfValues "Smalltalk method"\n ^self values\n inject: 0\n into: [ :sum :element | sum + element value]\n<<<\n \ninject 这样工作:第一次指定的block被执行的时候,sum被设成inject的参数(本例为0),element被设为数组的第一个元素。以后block被执行的时候,sum的值设为上次block执行后返回的值。这样,sum就可以记录总数了最后的inject的值是block最后一次执行后返回的值。 \nRuby 没有inject 方法,但我们可以很容易的写一个,在这个例子中我们把它加入Array类。 \n\n<<<\nclass Array \n def inject(n) \n each { |value| n = yield(n, value) } \n n \n end \n def sum \n inject(0) { |n, value| n + value } \n end \n def product \n inject(1) { |n, value| n * value } \n end \nend \n[ 1, 2, 3, 4, 5 ].sum » 15 \n[ 1, 2, 3, 4, 5 ].product » 120 \n<<<\n\n尽管block经常是用在[[迭代器]]中,但是,块也有其它一些有用的用处。
You can SaveChanges if you're using FireFox or InternetExplorer:\n# if you're using Windows XP you might run into ServicePack2Problems\n# right click on [[this link|#]] and select 'Save link as...' or 'Save target as...'\n** choose where to save the file, and what to call it (but keep the .HTML extension)\n# open the newly downloaded file in your browser\n# click the 'options' button to set your username\n# edit, create and delete the tiddlers you want\n** you can change the SpecialTiddlers to change the SiteTitle and MainMenu etc.\n# Every time you click "done" or "delete" when editing a Tiddler, your changes are saved and a backup of the last saved state is created (customize this in the options panel).\n
Released in December 2004, the [[second version|secondversion.html]] of TiddlyWiki grew 50% over the FirstVersion to 76KB. It added IncrementalSearch, the ReferencesButton, the PermaLinkButton, PermaView, CloseAll, SmoothScrolling, an ImprovedSidebar, an animation for the CloseButton and a tiny EasterEgg in homage to Macintosh OS X. It also introduced a new SiteDesign.
One of the neatest features of TiddlyWiki is that it is entirely self-contained in a single HTML file. It contains the actual hypertext document, and the JavaScript, CascadingStyleSheets and HTML necessary to both view and edit the document. This means that it is trivial to host a TiddlyWiki on a website, or to distribute one by email. And anyone with a reasonably recent web browser will be able to read and edit it.
"How do I run this on a server?" is the number one question people ask. \n\nThe answer is "You can't, and it's a feature, not a bug." \n\nThe idea behind TiddlyWiki is that you can update it from any device with a capable browser, whether you are connected or not. It's personal, not collaborative, though you could upload your version to your server if you wanted people to see your lists (PermaView is good for this).\n\nThe good news is that there are online versions of TiddlyWiki that you can find at [[Jeremy's site|http://www.tiddlywiki.com/#TiddlyWikiAdaptations]], and if you like the things I've done with GTDTiddlyWiki you could merge my version into other TiddlyWiki implementations.
Internet Explorer Windows XP SP2 seems to have a magical ability to keep track of html files that have been downloaded from the internet and saved on an NTFS drive. By storing additional data in an [[alternate data stream|http://www.jsware.net/jsware/sviewer.html]], it manages to keep them in the 'Internet Zone' regardless of attempts to rename or modify the file. But, in order to be able to SaveChanges, TiddlyWiki needs to run in the 'My Computer Zone'.\n\nThere are a couple of ways around the problem:\n* save the TiddlyWiki HTML file to a FAT drive (eg a USB thumb drive)\n* open the downloaded file with a text editor and save it again under a different name\n\nIn either case, The new file will open in 'My Computer Zone', which in turn causes Internet Explorer to put up it's information bar asking you whether you want to run it. You need to 'Allow blocked content' to let TiddlyWiki do it's stuff.\n\nThis is all a bit frustrating. An easy alternative is to use FireFox, which seems to do the trick on all platforms.
<<list shadowed>>
/***\n''Single Page Mode Plugin for TiddlyWiki version 1.2.35 or above''\n^^author: Eric Shulman - ELS Design Studios\nsource: http://www.elsdesign.com/tiddlywiki/#SinglePageModePlugin\nlicense: [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]^^\n\nNormally, as you click on the links in TiddlyWiki, more and more tiddlers are displayed on the page. The order of this tiddler display depends upon when and where you have clicked. Some people like this non-linear method of reading the document, while others have reported that when many tiddlers have been opened, it can get somewhat confusing.\n\n!!!!!Usage\n<<<\nSinglePageMode allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one item displayed at a time. You can select a checkbox in the AdvancedOptions tiddler to enable this behavior or revert to the standard TiddlyWiki multiple tiddler display behavior.\n\nWhen SinglePageMode is enabled, the title of the current tiddler is automatically displayed in the browser window's titlebar and the browser's location URL is updated with a 'permalink' for the current tiddler so that it is easier to create a browser 'bookmark' for the current tiddler.\n\n//Note: This feature currently effects ALL tiddler display behavior, including features that normally result in multiple tiddlers being displayed, such as the results of searches or the initial DefaultTiddlers shown when the document is loaded. //\n<<<\n!!!!!Configuration\n<<<\nWhen installed, this plugin automatically adds a checkbox in the AdvancedOptions tiddler so you can enable/disable the plugin behavior. You can also use the following ''control panel'' checkbox to change the current plugin handling:\n\n<<option chkSinglePageMode>> Display one tiddler at a time\n<<<\n!!!!!Installation\n<<<\nimport (or copy/paste) the following tiddlers into your document:\n''SinglePageModePlugin'' (tagged with <<tag systemConfig>>)\n^^documentation and javascript for SinglePageMode handling^^\n\nWhen installed, this plugin automatically adds a checkbox in the AdvancedOptions tiddler so you can enable/disable this behavior. However, if you have customized your AdvancedOptions, you will need to manually add ''"<< {{{option chkSinglePageMode}}} >> display one tiddler at a time"'' to your customized tiddler.\n<<<\n!!!!!Revision History\n<<<\n''2005.11.24 [1.1.2]''\nWhen the back and forward buttons are used, the page now changes to match the URL. Based on code added by Clint Checketts\n''2005.10.14 [1.1.1]''\npermalink creation now calls encodeTiddlyLink() to handle tiddler titles with spaces in them\n''2005.10.14 [1.1.0]''\nadded automatic setting of window title and location bar ('auto-permalink').\nfeature suggestion by David Dickens.\n''2005.10.09 [1.0.1]''\ncombined documentation and code in a single tiddler\n''2005.08.15 [1.0.0]''\nInitial Release\n<<<\n!!!!!Credits\n<<<\nThis feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]. Support for BACK/FORWARD buttons developed by Clint Checketts\n<<<\n!!!!!Code\n***/\n//{{{\nversion.extensions.SinglePageMode= {major: 1, minor: 1, revision: 2, date: new Date(2005,11,24)};\n\nif (config.options.chkSinglePageMode==undefined)\n config.options.chkSinglePageMode=false;\n\nconfig.shadowTiddlers.AdvancedOptions\n += "\sn<<option chkSinglePageMode>> Display one tiddler at a time";\n\nvar checkUrlId = 0;\nvar lastURL = window.location.hash;\nfunction checkLastURL()\n{\n if (!config.options.chkSinglePageMode)\n { window.clearInterval(checkUrlId); checkUrlId=0; return; }\n if (lastURL == window.location.hash)\n return;\n var tiddlerName = convertUTF8ToUnicode(decodeURI(window.location.hash.substr(1)));\n tiddlerName=tiddlerName.replace(/\s[\s[/,"").replace(/\s]\s]/,""); // strip any [[ ]] bracketing\n if (tiddlerName.length) window.displayTiddler(null,tiddlerName,1,null,null);\n}\n\nwindow.coreDisplayTiddler=window.displayTiddler;\nwindow.displayTiddler = function(src,title,state,highlightText,highlightCaseSensitive,animate,slowly)\n{\n if (config.options.chkSinglePageMode) {\n window.location.hash = encodeURIComponent(String.encodeTiddlyLink(title));\n lastURL = window.location.hash;\n document.title = getElementText("siteTitle")+" - "+title;\n closeAllTiddlers();\n if (!checkUrlId) checkUrlId=window.setInterval(function() {checkLastURL();},1000);\n }\n coreDisplayTiddler(src,title,state,highlightText,highlightCaseSensitive,animate,slowly);\n}\n\n//}}}\n
config.macros.singleSlideMode = {label:"slide mode"};\n\nconfig.macros.singleSlideMode.handler = function(place,macroName,params,wikifier,paramString,tiddler){\n if(tiddler instanceof Tiddler)\n {\n var title = tiddler.title;\n var onclick = function(e) {\n if (!e) var e = window.event;\n clearMessage();\n story.closeAllTiddlers(title);\n presentationMode();\n return false;\n };\n var lingo = config.views.wikified.toolbarCloseOthers;\n createTiddlyButton(place,this.label,lingo.tooltip,onclick);\n }\n}\n\nfunction presentationMode(){\n var contentWrapper = document.getElementById('contentWrapper');\n if (contentWrapper.className == "presentationMode"){\n contentWrapper.className = "";\n } else{\n contentWrapper.className = "presentationMode";\n }\n}
a guide to reach the road of Ruby
Ruby编程手册
/***\n!Slide Mode Styles\n***/\n/*{{{*/\n#contentWrapper.presentationMode,\n #contentWrapper.presentationMode #displayArea{\n width: 100%;\n font-size: 1.5em;\n margin: 0;\n padding: 0;\n }\n\n#contentWrapper.presentationMode #sidebar,\n#contentWrapper.presentationMode #mainMenu,\n#contentWrapper.presentationMode #header{\n display:none;\n}\n/*}}}*/
<div class='toolbar'><span macro='closeTiddler'></span><span macro='singleSlideMode'></span><span macro='closeOthers'></span><span macro='editTiddler'></span><span macro='permalink'></span><span macro='references'></span><span macro='jump'></span></div><div class='title' macro='view title'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='footer'>\n<span macro='tags'></span>\n</div>
TiddlyWiki uses several special tiddlers to hold the text used for the MainMenu, the SiteTitle and the SiteSubtitle. DefaultTiddlers is used to store the titles of the tiddlers that are shown at startup. SaveChanges is automatically displayed if there's a problem with saving. StyleSheet is a user defined stylesheet that exists as a Tiddler. \n\nAll except StyleSheet can be edited with the changes taking effect immediately.
When it loads, TiddlyWiki looks for the names of tiddlers to open as a space-separated list after the # in the URL. If there are no tiddlers in the URL it instead loads the tiddlers named in DefaultTiddlers, one of the SpecialTiddlers.
[[Good GTD]]
@media print {\n#mainMenu, #sidebar, #messageArea {display: none !important;}\n#displayArea {margin: 1em 1em 0em 1em;}\n\n\n/* LAYOUT ELEMENTS ========================================================== */\n*\n{\n margin: 0;\n padding: 0;\n}\n\nbody {\n background: #fff;\n color: #000;\n font-size: 6.2pt;\n font-family: "Lucida Grande", "Bitstream Vera Sans", Helvetica, Verdana, Arial, sans-serif;\n}\n\nimg {\n max-width: 2.2in;\n max-height: 4.3in;\n}\n\n#header, #side_container, #storeArea, #copyright, #floater, #messageArea, .save_accesskey, .site_description, #saveTest, .toolbar, .footer\n{\n display: none;\n}\n\n#tiddlerDisplay, #displayArea\n{\n display: inline;\n}\n\n.tiddler {\n margin: 0 0 2em 0;\n border-top: 1px solid #000;\n page-break-before: always;\n}\n\n.tiddler:first-child {\n page-break-before: avoid;\n}\n\n.title {\n font-size: 1.6em;\n font-weight: bold;\n margin-bottom: .3em;\n padding: .2em 0;\n border-bottom: 1px dotted #000;\n}\n\np, blockquote, ul, li, ol, dt, dd, dl, table\n{\n margin: 0 0 .3em 0;\n}\n\nh1, h2, h3, h4, h5, h6\n{\n margin: .2em 0;\n} \n\nh1\n{\n font-size: 1.5em;\n}\n\nh2\n{\n font-size: 1.3em;\n}\n\nh3\n{\n font-size: 1.25em;\n}\n\nh4\n{\n font-size: 1.15em;\n}\n\nh5\n{\n font-size: 1.1em;\n}\n\nblockquote\n{\n margin: .6em;\n padding-left: .6em;\n border-left: 1px solid #ccc;\n}\n\nul\n{\n list-style-type: circle;\n}\n\nli\n{\n margin: .1em 0 .1em 2em;\n line-height: 1.4em; \n}\n\ntable\n{\n border-collapse: collapse;\n font-size: 1em;\n}\n\ntd, th\n{\n border: 1px solid #999;\n padding: .2em;\n}\n\nhr {\n border: none;\n border-top: dotted 1px #777;\n height: 1px;\n color: #777;\n margin: .6em 0;\n}\n}
!Supported\n* Safari (requires [[plugin by Jonathan Paisley|http://www.dcs.gla.ac.uk/~jp/tiddlywiki/]])\n* Firefox\n* Win IE 6 (caveat: see KnownBugs)\n* Camino (I haven't verified this)\n\n!Unsupported\n* ==Safari: Saving doesn't work in Safari, which renders TiddlyWiki useless.== FIXED! Thanks to [[Jonathan Paisley|http://www.dcs.gla.ac.uk/~jp/]].\n* Opera: I've gotten mixed reports.
Stylesheet: <<option txtStyleSheet>>\nPage template: <<option txtPageTemplate>>\nTiddler view template: <<option txtViewTemplate>>\nTiddler edit template: <<option txtEditTemplate>>
Super-duper thanks to JeremyRuston for creating such a great Open Source project.\n \nThanks to Merlin Mann of 43Folders for his work evangelizing and expanding GTD and other life hacks.\n \nThanks to David Allen and Davidco. for coming up with such an elegant and powerful system for dealing with modern life.\n\nFinally, thanks to everyone who made comments and reported bugs.\n\nJeremy's original thank you follows:\n----\nThank you to everybody who has helped me with support and suggestions for TiddlyWiki, but especially IsaoSonobe for his cunning regular expression code, and to my friend RebeccaWelby for the SiteDesign.
This is the ThirdVersion of TiddlyWiki, released in April 2005. The SecondVersion was released in December 2004, and before that the FirstVersion in September 2004.\n\nSee the RevisionHistory for details of minor changes and bug-fixes since the ThirdVersion.
A TiddlyWiki is like a blog because it's divided up into neat little chunks, but it encourages you to read it by hyperlinking rather than sequentially: if you like, a non-linear blog analogue that binds the individual microcontent items into a cohesive whole. I think that TiddlyWiki represents a novel medium for writing, and will promote it's own distinctive WritingStyle. This is the ThirdVersion of TiddlyWiki, which adds several NewFeatures. There are also several TiddlyWikiAdaptations by other developers based on earlier versions.\n\nThe original TiddlyWiki is [[here|http://tiddlywiki.com]].
The first and original was [[PhpTiddlyWiki|http://www.patrickcurry.com/tiddly/]] from PatrickCurry and GabrielJeffrey that adds a simple ServerSide in PHP with MySQL. Patrick's site allows anyone to create and edit tiddlers, and has become the de facto community site around TiddlyWiki.\n\nSome of the other adaptations include:\n* HenrikAastedSorensen's at http://aasted.org/wiki\n* IsaoSonobe's OgreKitWiki at http://www-gauge.scphys.kyoto-u.ac.jp/~sonobe/OgreKit/OgreKitWiki.html \n* JacquesTurbé's TidliPo, in French at http://avm.free.fr/IMG/html/carnet_gt_BigCo.html\n* ChristianHauck's at http://www.christianhauck.net/html/14300.html\n* TonyLownds's at http://tony.lownds.com/home/\n* PoulStaugaard and IvanMetalnikov's at http://poul.staugaard.dk/IeWiki.htm\n\n* There's also KevemBuangga's TiddlyWikiClone at http://www.kevembuangga.com/hwk/hailiwiki.htm (caution: on Safari, it seems to get locked up with error alerts)
TiddlyWiki has been used as the basis of a couple of experiments in hypertext fiction. GinaTrapani created [[Baby Dog Sitter|http://scribbling.net/tiddlywiki-and-non-linear-fiction]] with the FirstVersion of TiddlyWiki, followed by "[[Die, Vampire! Die!|http://www.davidvanwert.com/wiki/dievampiredie.html]]" from DavidVanWert.
IsaoSonobe's TiddlyWikiPod is a nifty utility for Mac OS X that copies the content of a TiddlyWiki to an iPod where it can be read, and links followed, using the touch wheel. Isao has also added the ability to link to songs from the TiddlyWiki text which enables some interesting applications. At the moment, it only works with the older SecondVersion of TiddlyWiki. It can be found at http://www8.ocn.ne.jp/~sonoisa/TiddlyWikiPod/index.html
A row of ToolbarButtons appears to the right of a tiddler title when the mouse is hovered over it. The buttons are:\n* ''close'' - close the current tiddler\n* ''edit'' - edit the current tiddler\n* ''permalink'' - puts a link direct to the current tiddler into the address bar\n* ''references'' - displays all the tiddlers that link to the current tiddler\n* ''done'' - save all changes and create a backup\n* ''cancel'' - cancel changes to a tiddler being edited\n* ''delete'' - delete the current tiddler
[[tristones'blog|http://tristones.viaspeip.com]]
Supscribe to the GTDTW RSS newfeed at http://shared.snapgrid.com/feed/gtdtw.xml to be notified of official releases.
Within the main story column you can click on bold links to read a linked tiddler. Click on italic links to create a new tiddler. When you hover the mouse over a tiddler several ToolbarButtons appear. You can edit the text of any tiddler by double-clicking on it (or selecting 'edit' from the toolbar), but your changes won't get saved permanently until you make your own copy of TiddlyWiki, as described in SaveChanges.
Right click and "save as" the following links:\n[[1.0.4|/gtdtw-archive/gtdtw1.0.4.html]]\n[[1.0.3|/gtdtw-archive/gtdtw1.0.3.html]]\n[[1.0.2|/gtdtw-archive/gtdtw1.0.2.html]]\n[[1.0.1|/gtdtw-archive/gtdtw1.0.1.html]]\n[[1.0.0|/gtdtw-archive/gtdtw1.0.0.html]]
<div class='toolbar'><span macro='closeTiddler'></span><span macro='editTiddler'></span><span macro='permalink'></span><span macro='references'></span></div><div class='title' macro='view title'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='footer'>\n<span macro='tags'></span>\n</div>
Putting TiddlyWiki on a USB thumb drive lets you carry around a SelfContained notebook that you can update wherever there's a reasonably modern computer, whether it's a Mac, Linux or a PC. (To be even more independent you can [[install FireFox on the drive|http://www.mozilla.org/support/firefox/tips#oth_usb]] as well).
A Wiki is a popular way of building collaborative websites. It's based on the ideas of easy editing of pages and the use of special WikiWord notation to automagically create links between pages. See Wikipedia for [[more details|http://en.wikipedia.org/wiki/Wiki]]. TiddlyWiki is different from a conventional Wiki because it is not based on entire pages of content, but rather items of MicroContent that are referred to as 'tiddlers'.
A WikiWord is a word composed of a bunch of other words slammed together with each of their first letters capitalised. WikiWord notation in a conventional WikiWikiWeb is used to name individual pages while TiddlyWiki uses WikiWord titles for smaller chunks of MicroContent. Referring to a page with a WikiWord automatically creates a link to it. Clicking on a link jumps to that page or, if it doesn't exist, to an editor to create it. This ThirdVersion of TiddlyWiki also adds NonWikiWordLinks.
I'm hoping that after using TiddlyWiki for a while a new WritingStyle will emerge that is appropriate for this medium. Jakob Neilsen wrote an article about [[writing styles|http://www.useit.com/alertbox/980906.html]] for MicroContent back in 1998 that still seems surprisingly relevant.
Ruby的 case 表达式非常强大,就像多个if的固化物一样。 \n\n<<<\ncase inputLine\n when "debug" \n dumpDebugInfo \n dumpSymbols\n when /p\ss+(\sw+)/ \n dumpVariable($1)\n when "quit", "exit" \n exit\n else \n print "Illegal command: #{inputLine}" \nend \n<<<\n\n像if一样,case返回最后执行的语句的结果,如果你的when和后面的语句都在一行,你也需要加一个then关键字。\n\n<<<\nkind = case year\n when 1850..1889 then "Blues"\n when 1890..1909 then "Ragtime"\n when 1910..1929 then "New Orleans Jazz"\n when 1930..1939 then "Swing"\n when 1940..1950 then "Bebop"\n else "Jazz"\n end\n<<<\n\ncase 操作符根据case后面目标的值,跟每个when后面的值用===进行判断, \noperates by comparing the target (the expression after the keyword case) with each of the comparison expressions after the when keywords. This test is done using comparison === target. As long as a class defines meaningful semantics for === (and all the built-in classes do), objects of that class can be used in case expressions.\n\n\nFor example, regular expressions define === as a simple pattern match. \n<<<\ncase line\n when /title=(.*)/\n puts "Title is #$1"\n when /track=(.*)/\n puts "Track is #$1"\n when /artist=(.*)/\n puts "Artist is #$1"\nend\n<<<\n\nRuby classes are instances of class Class, which defines === as a test to see if the argument is an instance of the class or one of its superclasses. So (abandoning the benefits of polymorphism and bringing the gods of refactoring down around your ears), you can test the class of objects: \n<<<\ncase shape\n when Square, Rectangle\n # ...\n when Circle\n # ...\n when Triangle\n # ...\n else\n # ...\nend\n<<<\n \n
! 单子(Singletons)和其他构造函数 \n\n有时候,你想改变缺省的对象的创建方式,比如,对于我们的点唱机系统,我们有很多点唱机,遍布全国,我们想尽可能的使他容易维护,所以我们需要记录点唱机发生的所有事情,比如一首歌被播放了,收钱了等,所以我们需要一个日志类。因为我们想把带宽留给音乐数据,所以日志记录在本机。我们想一个点唱机系统只有一个log类,并被系统中的所有类共有使用。 \n\n通过使用单子模式,要想使用这个log类,只有一种创建方法:Logger.create,并且确保系统中只有一个log的实例存在。 \n\n<<<\nclass Logger\n private_class_method :new\n @@logger = nil\n def Logger.create\n @@logger = new unless @@logger\n @@logger\n end\nend\n<<<\n\n我们把logger类的new方法设成了私有的,这样就不能用Looger.new来创建logger对象了。我们提供了一个类方法 Logger.create ,用到了__类变量 @@logger ,这是一个指向logger类实例的引用__。可以看到,如果实例已经创建了,这个方法直接返回已经创建的实例,不会再创建第二个。[这里的实现是非线程安全的,如果有多个线程来访问这个函数,可能会出产生多个logger对象。我们可以用ruby提供的Singleton mixin来解决,而不必自己处理线程安全问题。]我们可以检查一下这两个方法的返回情况。 \n\n<<<\nLogger.create.id }} 537766930 \nLogger.create.id }} 537766930 \n<<<\n\n用类方法来包装构造函数,也可以让使用你的类的人感到轻松。比如我们的类Shape代表一个多边形,构造函数接收边数和周长:\n\n<<<\nclass Shape\n def initialize(numSides,perimeter)\n end\nend\n<<<\n\n但是,多年以后,使用方法变了,现在需要提供shape的名称,边数,和边长而不是周长。而我们只需要加几个类方法就行了:\n\n<<<\nclass Shape\n def Shape.triangle(sideLength)\n Shape.new(3, sideLength*3)\n end\n def Shape.square(sideLength)\n Shape.new(4, sideLength*4)\n end\nend\n<<<
变量用来跟踪一个对象的状态,是指向其他对象的一个引用 。 \n\n<<<\nperson = "Tim" \nperson.id => 537771100 \nperson.type => String \nperson => "Tim" \n<<<\n\n第一行,我们创建了一个新字符串对象"Tim",person是指向这个字符串对象的一个引用,下两行的测试语句显示了这个对象的类型和id,最后显示了它的值。 \n\n但变量是对象吗? \n\n在ruby中,答案是否定的。__一个变量只是指向一个对象的引用。__这些对象可能正在某地,比如堆栈中,变量只是指向了这些对象。\n我们再看看稍微负责的例子 \n\n<<<\nperson1 = "Tim" \nperson2 = person1 \n person1[0] = 'J' \n person1 }} "Jim" \n person2 }} "Jim" \n<<<\n\n我们改变了person1的第一个字符,但是第二个也跟着改了。这是因为变量只是指向一个对象的引用,而不是对象本身。赋值语句person2 = person1 没有创建新的对象,只是person2拷贝了person1的引用而已。所以person1和person2都指向了同一个对象。 \n有时候赋值语句只是为对象建立了别名,而潜在的创建了新的变量指向同一个对象。这在我们的代码中可能会引起问题,但并不像你想的那么容易出错。我们可以用String的dup方法,这个方法会创建一个新的字符串对象,并且内容和消息接受者(方法执行者)一样。\n\n<<<\nperson1 = "Tim" \nperson2 = person1.dup \nperson1[0] = "J" \nperson1 }} "Jim" \nperson2 }} "Tim" \n<<<\n\n如果你不想别人修改一个对象,也可以冻结(freezing)这个对象。如果你修改一个被冻结的对象,ruby会抛出一个TypeError异常。 \n\n<<<\nperson1 = "Tim"\nperson2 = person1\nperson1.freeze # freeze方法防止对象修改\nperson2[0] = "J"\n\n \nproduces: prog.rb:4:in `=': can't modify frozen string (TypeError)\n from prog.rb:4\n<<<\n \n
while,until和for循环内建于Ruby语言之中,没有引入新的作用域,前面定义的局部变量可以在循环中使用,在循环中创建的变量在后面的代码也可以使用。\n\n而对loop或each使用block来说则不一样了。在这个block中创建的变量在外面是不能访问的。\n\n<<<\n[ 1, 2, 3 ].each do |x|\n y = x + 1\nend\n[ x, y ]\n<<<\n \nproduces: prog.rb:4: undefined local variable or method `x'\nfor #<Object:0x401c2ce0> (NameError) \n\n然而,如果block中的变量和前面已经定义的变量重名的话,已经存在的变量将会在块中使用,而在块执行完成后,这个变量的值也会改变。下面的例子,我们看到block执行之后,两个变量都改变了。\n<<<\nx = nil \ny = nil \n[ 1, 2, 3 ].each do |x| \n y = x + 1 \nend \n[ x, y ] » [3, 4] \n<<
! 在事务处理中使用块\nblock也可以用作定义一块代码,这些代码必须在一定的事务控制下运行。比如,你经常会打开一个文件,对内容作一些处理,然后需要确保文件在最后会被关闭。尽管我们可以用常规的方法实现,但是,我们可以让文件对象自己负责关闭它。一个简单例子如下(忽略了错误处理等):\n\n<<<\nclass File\n def File.openAndProcess(*args)\n f = File.open(*args)\n yield f\n f.close()\n end\nend\n\nFile.openAndProcess("testfile", "r") do |aFile| \n print while aFile.gets \nend\n<<< \nproduces: This is line one\nThis is line two\nThis is line three\nAnd so on...\n\n这个小例子阐述了几个技术点。方法openAndProcess 是一个类方法,这个方法可以独立于任何File对象来单独调用,即不需要生成类的实例。__我们在这个方法的参数列表中使用了 *args,这表示所有调用时候的参数将作为数组传递到这个方法。__而这个参数是传递给File.open方法的。\n\n一旦这个文件被打开,openAndProcess 将调用yield,然后将打开的文件对象传递给这个block。当block返回后,这个文件将被关闭。这种情况下,关闭文件的任务就从使用文件对象的用户转变为文件本身了。\n\n最后,这个例子用do..end来定义一个块,这和用两个花括号定义一个块只是有优先级别的区别,将在后面讨论。\n\n让文件自己管理自己的生命周期十分有用,Ruby自带的File类就提供了这样的支持。如果File.open调用时指定了一个block,那么这个块就会用传递过来文件对象作为参数执行,然后,当块结束后,这个文件会被文件对象关闭。这很有趣,也就是说__File.open方法有两个版本,一个接受block,一个不接受block。__当没有指定block调用这个方法的时候,这个方法只会返回一个打开的文件对象。方法Kernel::block_given?提供了实现这种功能的可能,如果调用的时候给了一个block,这个方法将返回true,这样,你也可以实现自己open方法\n\n<<<\nclass File\n def File.myOpen(*args)\n aFile = File.new(*args)\n # If there's a block, pass in the file and close\n # the file when it returns\n if block_given?\n yield aFile\n aFile.close\n aFile = nil\n end\n return aFile\n end\nend\n<<<\n\n下一小节,我们谈谈[[块和闭包]]
我们要在SongList中修改[ ] 方法,使它能接受一个字符串参数,返回以此为标题的歌曲的。看起来我们很容易可以实现:我们有一个包含了很多Song对象的对象的数组,我们只需循环遍历整个数组,找到匹配的那个就可以了。\n\n<<<\nclass SongList\n def [](key)\n if key.kind_of?(Integer)\n return @songs[key]\n else\n for i in 0...@songs.length\n return @songs[i] if key == @songs[i].name\n end\n end\n return nil\n end\nend\n<<<\n \n这样已经可以工作了,而且看上去很符合常规:用一个for循环来遍历数组。\n有没有更自然的方法呢?\n当然有,我们可以用[[Enumerable#find]]方法。\n\n<<<\nclass SongList\n def [](key)\n if key.kind_of?(Integer)\n result = @songs[key]\n else\n result = @songs.find { |aSong| key == aSong.name }\n end\n return result\n end\nend\n<<< \n\n我们可以用if修饰符来使代码更简短一些。\n\n<<< \nclass SongList\n def [](key)\n return @songs[key] if key.kind_of?(Integer)\n return @songs.find { |aSong| aSong.name == key }\n end\nend\n<<< \n\n方法find就是一个[[迭代器]],这个方法重复不断地执行一个给定的block。[[块]]和[[迭代器]]都是Ruby中比较有趣的特点。我们后面会进一步来讨论这些特点。先继续讨论如何[[实现迭代器]]\n
! 块和闭包\n让我们再回来看看自动点唱机,某些时候,我们需要处理点唱机和用户的界面:很多按钮,供用户选择歌曲和控制播放,我们需要给这些按钮指定相应的时间处理代码,而Ruby中的block就很适合干这样的事情。假设点唱机的设计者通过Ruby扩展为我们提供了一个基本的按钮类。\n<<<\nbStart = Button.new("Start")\nbPause = Button.new("Pause")\n# ...\n<<<\n当用户按下按钮之后如何处理呢?Button类提供了一个buttonPressed方法,在按钮按下时能被回调。所以最简单的方法创建Button的子类,然后在每个子类中实现buttonPressed 方法。\n<<<\nclass StartButton < Button\n def initialize\n super("Start") # invoke Button's initialize\n end\n def buttonPressed\n # do start actions...\n end\nend\n\nbStart = StartButton.new \n<<<\n\n这样做有两个问题,首先这样将产生大量子类,如果Button变化了,所有子类都需要维护;第二,按钮按下之后需要执行的行为不应该在按钮上表示,这是点唱机的责任。我们可以用块来消除这些问题\n\n<<<\nclass JukeboxButton < Button\n def [[initialize]](label, &action)\n super(label)\n @action = action\n end\n def buttonPressed\n @action.[[call]](self)\n end\nend\nbStart = JukeboxButton.new("Start") { songList.start } \nbPause = JukeboxButton.new("Pause") { songList.pause }\n<<< \n\n__上面代码的关键点在JukeboxButton#initialize的第二个参数,这个参数前面带有一个&符号,在Ruby中代表这个参数是一个块,这个块将会被转化为一个Proc对象,并关联到相应变量。__在本例中我们把它赋给实例变量@action 。当回调方法buttonPressed 执行时,我们用方法Proc#call来调用相应的block。\n\n当创建一个Proc对象之后我们得到的是什么呢?很有趣,我们得到的不仅是一串代码。和这个block定义相关联的上下文环境(范围内的):self值,定义它的方法,变量,常量等。Ruby中的一个有趣的地方就是即使block定义时候的变量已经不在它的使用范围内,这个变量还保留着,仍可以使用 \n我们来看一个例子,这个例子用了方法[[proc]],这个方法把一个block变为了一个Proc对象。\n\n<<<\ndef nTimes(aThing) \n return [[proc]] { |n| aThing * n } \nend \n \np1 = nTimes(23) \np1.[[call]](3) » 69 \np1.[[call]](4) » 92 \np2 = nTimes("Hello ") \np2.[[call]](3) » "Hello Hello Hello " \n<<<\n\n方法nTimes 返回一个Proc对象,这个对象引用了这个函数的参数:aThing 。即使这个参数在块被调用时已经不在自己的作用域里了,这个块还是可以访问这个参数。(比如p1.call(4),这个时候,虽然对p1的赋值语句中的参数23已经超出了作用域范围,但是它仍然保存着23×4=92。)\n\n下一节谈ruby的基本数据类型:[[标准类型]]
! 字符串 Strings\n\nRuby的字符串是简单的8位字节(8-bit bytes)序列。它们通常保存可打印字符序列,但是这不是必须的;一个字符串也可以保存二进制数据。字符串是String类的对象。 \n\n字符串通常用字符常量建立---包括在分隔符里面的字符序列。因为二进制数据很难在程序代码里面表达,你可以在一个字符串常量里面使用各种转义字符。每个转义字符都会在程序编译的时候转换成相应的二进制数值。分隔符的种类表明了取代作用的程度。用单引号刮住的字符串里,两个连续的反斜杠会被一个反斜杠取代,一个反斜杠后面跟一个单引号变成一个单引号。\n<<<\n'escape using "\s\s"' }} escape using "\s" \n'That\s's right' }} That's right \n<<<\n\n用双引号括住的字符串支持更多的转义字符。最常见的转义字符可能是"\sn"了,代表一个换行符。第203页的表18.2列出了完整的转义字符。__另外,你可以用 #{ expr } 来把任何的Ruby表达式的值插入到字符串中。如果那个表达式是全局变量,类变量或者实例变量,你可以省略花括号。__\n<<<\n"Seconds/day: #{24*60*60}" => Seconds/day: 86400 \n"#{'Ho! '*3}Merry Christmas" => Ho! Ho! Ho! Merry Christmas \n"This is line #$." => This is line 3 \n<<<\n\n还有三种方法来构建字符串常量:%q, %Q和“here documents.”\n\n%q 和 %Q用来界定单引号和双引号的范围。\n<<<\n%q/general single-quoted string/ => general single-quoted string \n%Q!general double-quoted string! => general double-quoted string \n%Q{Seconds/day: #{24*60*60}} => Seconds/day: 86400 \n<<<\n\n跟在'q'或者'Q'后面的字符是分隔符,如果那个字符是括号,大括号,圆括号或者小于等于符号,那么程序会一直向下读直到遇见最近的停止符号,或者到匹配到相应的符号才停止,然后把读入的字符作为一个字符串整体。\n\n最后,你可以用"here document"构建字符串。\n<<<\naString = <<END_OF_STRING\n The body of the string\n is the input lines up to\n one ending with the same\n text that followed the '<<'\nEND_OF_STRING\n<<<\n\n一个 here document 由包含在开始到一个由你在'<<'后面指定的结束符之间的(但是不包括结束符)多行字符串组成。一般的,这个结束符必须在第一列开始,但是如果你在'<<'后面加一个减号,你就可以缩进结束符了。\n<<<\nprint <<-STRING1, <<-STRING2\n Concat\n STRING1\n enate\n STRING2\n<<<\n \n产生结果: \nConcat\nenate\n\n \n
\n在这个例子中,yield接收一个参数,这个参数将会在执行的时候传递给指定的块。在块的定义中,参数用两个竖线括起来,放在最前面。在这个例子中f用来接收yield传递的参数,所以,这个块才能打印这个序列。一个块可以接受任意个参数。@@__如果一个块的参数和yield中传递的参数个数不一样,将会怎样呢?很巧合,这和我们在并行赋值(parallel assignment)中谈到的原则一样(如果一个block只接收一个参数,而yield提供的参数多于1个,那么这些参数将被转化为一个数组。)__@@\n\n传递给一个块的参数可以是存在的局部变量,如果是这样的话,那么这个局部变量的新值(如果在块中被修改了)在块退出后将会保留,这可能会有一定的副作用,但是这样做有一个性能方面的考虑。\n一个块也可以返回一个结果给调用它的方法。__这个块中的最后一个表达式的值将会返回给方法__,Array中的find方法就是这样工作的。(find在Enumerable中定义,被插入到了类Array)\n\n<<<\nclass Array \n def find \n for i in 0...size \n value = self[i] \n return value if yield(value) \n end \n return nil \n end \nend \n \n[1, 3, 5, 7, 9].find {|v| v*v > 30 } » 7 \n<<<\n\n这个用法中数组将连续的元素传递给指定的块,如果这个块返回true,则这个方法返回当前对应的元素值,如果没有符合的值,则返回nil。这个方法显示了迭代器的好处,Array类只作自己应该做的,访问数组元素,而应用代码只关注于特殊的需求。\n\nRuby中的集合对象中也包含其它一些常用迭代器,其中之二是[[Array#each]]和collect。__[[Array#each]]可以认为是最简单的迭代器,它们都会对集合的每个元素来调用块。__\n\n__另一个是[[Array#collect]],它跟each类似,它将集合中的元素传递给一个块,在块中处理后返回一个包含处理结果的新数组。__\n\n为了更加了解ruby的特性,我们可以看一下[[Ruby和c++,java的比较]],或者直接前进到[[在事务处理中使用块]]
! 数组Arrays\n数组类包含了若干个对其它对象的引用,每个引用在数组的一个位置上,用一个正整数来索引。\n\n你可以直接指定一组值来创建一个数组,或者用数组类的new方法。用第一种方法创建数组要用中括号把各个元素括起来,每个元素之间用逗号隔开。\n\n<<<\na = [ 3.14159, "pie", 99 ] \na.type » Array \na.length =» 3 \na[0] =» 3.14159 \na[1] =» "pie" \na[2] =» 99 \na[3] =» nil \n \nb = Array.new \nb.type =» Array \nb.length =» 0 \nb[0] = "second" \nb[1] = "array" \nb =» ["second", "array"] \n<<<\n\n__数组指定索引的下标用[ ]操作符,这实际上也是一个方法,可以在子类中被重载。__数组索引从0开始,从左向右计数,如果指定的索引为负数,则表示从右边开始计数(这时候最右边的索引下标为-1,不是0)。\n\n<<<\na = [ 1, 3, 5, 7, 9 ] \na[-1] » 9 \na[-2] » 7 \na[-99] » nil\n<<< \n\n你也可以一对数字[start, count]作为下标,这将返回一个数组,包含原数组中从start开始的count个元素。\n\n<<<\na = [ 1, 3, 5, 7, 9 ] \na[1, 3] » [3, 5, 7] \na[3, 1] » [7] \na[-3, 2] » [5, 7] \n<<<\n \n 最后,你也可以在数组下标中使用[[Ranges]]作为索引。Range可参看下一章。__Range的起始值之间如果是2个点号,则包括最后的结束值,如果是3个点号,则Range的值不包括最后的那个边界值。__\n\n<<<\na = [ 1, 3, 5, 7, 9 ] \na[1..3] » [3, 5, 7] \na[1...3] » [3, 5] \na[3..3] » [7] \na[-3..-1] » [5, 7, 9] \n<<<\n\n__[ ]方法有一个对应的 []= 方法,这个方法是用来给指定的位置设置新的值,如果数组的下标位置超过了数组的大小,那么指定的下标将被设为指定的值,而中间没有涉及到的位置为设为nil。__如下面例子数组最大下标为4,而对a[6]设置新值,a[5]则被设为nil。\n\n<<<\na = [ 1, 3, 5, 7, 9 ] » [1, 3, 5, 7, 9] \na[1] = 'bat' » [1, "bat", 5, 7, 9] \na[-3] = 'cat' » [1, "bat", "cat", 7, 9] \na[3] = [ 9, 8 ] » [1, "bat", "cat", [9, 8], 9] \na[6] = 99 » [1, "bat", "cat", [9, 8], 9, nil, 99] \n<<<\n\n如果在[]= 方法中下标索引为两个数字(一个开始位置,一个长度)或者一个Range,则对应的一系列值将被重新设置。如果第二个参数即长度为0,则右边的值将被插入当前位置,没有值会被删除。如果[ ]=右边的长度和左边下标中指定的长度不一样,则原数组自动进行调整。\n\n<<<\na = [ 1, 3, 5, 7, 9 ] =» [1, 3, 5, 7, 9] \na[2, 2] = 'cat' =» [1, 3, "cat", 9] \na[2, 0] = 'dog' =» [1, 3, "dog", "cat", 9] \na[1, 1] = [ 9, 8, 7 ] =» [1, 9, 8, 7, "dog", "cat", 9] \na[0..3] = [] =» ["dog", "cat", 9] \na[5] = 99 =» ["dog", "cat", 9, nil, nil, 99] \n<<<\n\n数组有很多有用的方法,使用这些方法你能用数组实现队列,堆栈,列表等各种数据结构。\n\n! 哈希Hashes\n\n哈希Hashes (有时被称为关联数组或目录) 跟数组类似, 他为集合中的所有对象引用建立索引。\n你可以用任何类型的对象(objects of any type: strings, regular expressions等等)索引哈希表。 当你在哈希中存储了一个值, 你实际上提供了两个对象---[[键]]key和[[值]]value. 你可以随后用键取出存储值。 哈希中的值可以是任何类型的. \n下例使用哈希定义,使用花括号限定的一组键=>值对。\n\n<<<\nh = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' } \n \nh.length » 3 \nh['dog'] » "canine" \nh['cow'] = 'bovine' \nh[12] = 'dodecine' \nh['cat'] = 99 \nh » {"cow"=>"bovine", "cat"=>99, 12=>"dodecine", "donkey"=>"asinine", "dog"=>"canine"} \n<<<\n\n和数组相比, 哈希有一个明显的好处: 他们可以使用任何对象作为索引. 但是,他们也有明显的缺点: 他们的元素排列是无规则的, 所以你不能很方便的把哈希当作堆栈或者队列使用. \n\n你将发现哈希表在Ruby中并不是最常用的数据结构。\n\n经过简单的介绍了数组和哈希表之后,我们准备实现一个自动点唱机列表的三个基本方法.\n\n<<<\nappend( aSong ) » list \nAppend the given song to the list. \ndeleteFirst() » aSong \nRemove the first song from the list, returning that song. \ndeleteLast() » aSong \nRemove the last song from the list, returning that song. \n[ anIndex } » aSong \n<<<\n\n返回根据索引识别的歌曲,索引可能是整数或者歌曲名。\n\n这个列表给我们一个继续完善代码的线索。append方法,使之可以在歌曲列表末尾追加(append)歌曲的能力,还有deleteFirst、deleteLast可以在歌曲列表的首或尾删除歌曲。根据上面实现的三个方法,我们可以建议使用一个数组即可。因为这种在列表中返回一个歌曲位置的整数索引值的能力,数组就可以办到。\n\n但是,我们也需要从曲名取歌曲的方法,这样的需求用哈希表比较合适。曲名作为键,歌曲作为值。那么,我们能用哈希表办到吗?也许可以,但是这里也有问题。\n首先:哈希表不能有效排序。所以我们需要使用一个辅助数组保持对列表列的跟踪。更大的问题哈希表并不支持多个键有相同的值。对我们的播放列表来说,这就是一个问题。同一首歌可能被存储在歌曲列表中好几次。所以,目前我们使用歌曲列表的数组。当需要时,搜索它的标题。是否这将变成一个性能的瓶颈,我们可以稍后使用某类哈希表来比较(查找)。\n\n我们用基本initialize初始化我们的类。它建立一个数组来存储歌曲,另外存储一个实例变量@songs的引用。\n\n<<<\nclass SongList\n def initialize\n @songs = Array.new\n end\nend\n<<<\n\nSongList#append方法在@songs数组末尾追加一个给定的歌曲。它也返回它本身-一个当前歌曲列表对象SongList的引用。这是一个有用的惯例, 让我们能够把多个调用串联起来追加。\n\n<<<\nclass SongList\n def append(aSong)\n @songs.push(aSong)\n self\n end\nend\n<<<\n\n我们使用[[Array#shift]] 和 [[Array#pop]]方法增加另外两个方法deleteFirst 和 deleteLast\n\n<<<\nclass SongList\n def deleteFirst\n @songs.shift\n end\n def deleteLast\n @songs.pop\n end\nend\n<<<\n\n在这里, 先进行一次快速测试. 首先, 我们添加四首歌。我们将利用歌曲列表对象使用串联追加的方法也可以返回列表对象的事实。\n\n<<<\nlist = SongList.new\nlist.\n append(Song.new('title1', 'artist1', 1)).\n append(Song.new('title2', 'artist2', 2)).\n append(Song.new('title3', 'artist3', 3)).\n append(Song.new('title4', 'artist4', 4))\n<<<\n\n然后将检查从列表首位取值是否正确,如果列表为空的话,将返回nil.\n\n<<<\nlist.deleteFirst » Song: title1--artist1 (1) \nlist.deleteFirst » Song: title2--artist2 (2) \nlist.deleteLast » Song: title4--artist4 (4) \nlist.deleteLast » Song: title3--artist3 (3) \nlist.deleteLast » nil \n<<<\n\n我们的下一个方法是 [], 它使用索引访问列表元素。如果索引为一个数字 (我们可以使用 [[Object#kind_of]]?检查 ), 仅仅返回那个位置的元素。\n\n<<<\nclass SongList\n def [](key)\n if key.kind_of?(Integer)\n @songs[key]\n else\n # ...\n end\n end\nend\n<<<\n \n检查一下表现。 \n\n<<<\nlist[0] » Song: title1--artist1 (1) \nlist[2] » Song: title3--artist3 (3) \nlist[9] » nil \n<<<\n\n现在需要增加根据歌曲名查找歌曲的方法。这将牵扯到在歌曲列表对象中扫描歌曲的问题。检查每一个曲名,想要如此,我们要再花一点篇幅讲一下在此之下的另外一个ruby的特性:[[块和迭代]]\n
一个自动点唱机只有一首歌恐怕不会太流行,所以我们需要建立一个歌曲目录和一个等待播放的列表。这都是容器的例子,一个包含若干个对其它对象引用的对象。 \n 目录和播放列表都有类似的操作,增加歌曲,删除歌曲,返回歌曲列表等等。播放列表可能还需要别的方法,比如插入广告,记录累计播放时间等,我们将在后面考虑这些问题。现在,我们需要建立一个SongList类,以便在目录和播放列表中使用。\n\n 在开始实现之前,我们要知道怎么在SongList中存储歌曲列表。我们有三个明显得选择:Ruby的提供的Array,Ruby提供的Hash,或者我们自己创建一个列表结构。下面我们来看看数组合和哈希,然后选择一个来在我们的类中使用。
Song对象有一些内部属性,比如名称和演唱者,这些属性都是私有的,其他对象都不能直接访问。一般来说,这样是不错的设计,每个对象只负责自己的完整性,一致性。\n\n但是,如果把对象装饰的这么秘密将会使这些对象变得毫无作用,我们能创建它,但是我们不能修改它的属性。所以,我们可以定义一些方法,通过这些方法,外部对象可以访问,修改对象的属性。这些从外面看起来表现叫做属性(attributes)。\n\n\n对于我们Song对象,我们可能需要访问它的名字和演唱者,以便在播放的时候打印出来,还有它的时长(可以用类似进度条来显示)。\n \n//{{{\nclass Song \n def name \n @name \n end \n def artist \n @artist \n end \n def duration \n @duration \n end \nend \naSong = Song.new("Bicylops", "Fleck", 260) \naSong.artist => "Fleck" \naSong.name => "Bicylops" \naSong.duration => 260 \n//}}}\n\n这里,我们定义了三个访问方法,每个方法返回一个实例属性。在实际中,这些操作很普遍,所以ruby提供了一个方便的方法:用[[attr_reader]],它将为我们自动创建访问方法。可以成为[[可读属性]]\n\n//{{{\nclass Song \n attr_reader :name, :artist, :duration \nend \naSong = Song.new("Bicylops", "Fleck", 260) \naSong.artist => "Fleck" \naSong.name => "Bicylops" \naSong.duration => 260 \n//}}}\n\n这个例子引入了一些新东西,比如 ":artist"可以当作一个表达式,返回一个指向artist的符号链接。也可以把":artist"当作是artist的名字。这个例子里,我们定义了三个访问方法: name, artist, duration。而实例变量@name, @artist, @duration会自动创建。这样定义访问方法和我们上面写的一样。 \n\n! 可写属性\n\n有时候需要在外部对对象的属性进行修改。比如,一首歌的时长这个属性可能开始的时候只是一个估算的值,当第一次播放的时候,我们知道了它的真正时长,并且要把它写回到Song这个对象。 \n\n在Ruby中,可以象其他变量一样访问属性,比如上面我们调用了aSong.name ,所以我们也应该像变量一样给属性赋值。在ruby中,这样做就行: \n\n//{{{\nclass Song \n def duration=(newDuration) \n @duration = newDuration \n end \nend \naSong = Song.new("Bicylops", "Fleck", 260) \naSong.duration }} 260 \naSong.duration = 257 # set attribute with updated value \naSong.duration }} 257 \n//}}}\n\n赋值语句"aSong.duration = 257"调用了aSong中的方法duration= 参数为257 。实际上,一个方法名以=结尾,就像这个属性出现左边的赋值语句一样。同样,ruby也为创建可写属性提供了一个快捷方式\n \n//{{{\nclass Song\n attr_writer :duration\nend\naSong = Song.new("Bicylops", "Fleck", 260)\naSong.duration = 257\n//}}}\n\n! 虚拟属性\n\n这些属性访问方法不是对一个对象的实例变量的包装,比如,你需要得到以分钟为单位的时长,而不是以秒为单位:\n\n//{{{\nclass Song \n def durationInMinutes \n @duration/60.0 # force floating point \n end \n def durationInMinutes=(value) \n @duration = (value*60).to_i \n end \nend \naSong = Song.new("Bicylops", "Fleck", 260) \naSong.durationInMinutes => 4.333333333 \naSong.durationInMinutes = 4.2 \naSong.duration => 252 \n//}}}\n\n这里我们用属性方法建立了一个虚拟的实例变量,对于外面来说durationInMinutes可以看作和其他一样的属性,但实际上,并没有与之对应的实例变量。 \n\n这并不止是有趣而已,在Bertrand Meyer 的杰作[[《Object-Oriented Software Construction》]] 中,作者称这叫做@@统一访问原则(Uniform Access Principle)@@。通过把这些实例变量和他们计算之后的值隐藏起来,你就可以不用在自己的实现里来处理这些问题,而且,当需要改动的时候,你只需要改动一个文件,而不是很多文件。
<<<\nprintf("Number: %s5.2f,\snString: %s\sn",1.23,"hello")\n<<<\n输入\n Number: 1.23,\n String: hello\n\nRuby的一个特殊全局变量[[&_]]\nRuby的预定义对象[[ARGF]],用来读入程序输入文件\n ARGF.[[each]] {|line| print line if line =~/Ruby/}\n上面的语句可以改写为\n print ARGF.[[grep]](/Ruby/)
不要告诉他人,Ruby支持原始的灵巧的内建循环结构。\n\nwhile循环根据它的条件的真假来执行0次或者多次语句,比如,下面程序将一直运行,直到输入被打断。\n\n<<<\nwhile gets\n # ...\nend\n<<<\n \n\nutil也可以用来循环,知道条件为真,才停止操作。\n\n<<<\nuntil playList.duration > 60\n playList.add(songList.pop)\nend\n<<<\n \n\n\n像if和unless一样,while和until也可以用作语句操作符。 \n<<<\na *= 2 while a < 100\na -= 10 until a < 100\n<<<\n \n\n在前面的布尔表达式中,我们说过range也可以作为布尔表达式,这个机制多用于循环中,在下面的例子中,我们从一个包含从first到tenth的数字的文本文件中读取数据,但是只打印从以third开头的行,直到遇到fifth开头的行为止。\n\n<<<\nfile = File.open("ordinal")\nwhile file.gets\n print if /third/ .. /fifth/\nend\n<<<\n \n打印结果: third\nfourth\nfifth\n\n \n\n\nThe elements of a range used in a boolean expression can themselves be expressions. These are evaluated each time the overall boolean expression is evaluated. For example, the following code uses the fact that the variable $. contains the current input line number to display line numbers one through three and those between a match of /eig/ and /nin/. \n<<<\nfile = File.open("ordinal")\nwhile file.gets\n print if ($. == 1) || /eig/ .. ($. == 3) || /nin/\nend\n<<<\n \nproduces: first\nsecond\nthird\neighth\nninth\n\n \n\n这里有一点需要注意,当while和until用作语句修饰符的时候,如果它们修饰的语句以begin开头,end结尾,这段代码将总会执行,而不管后面的条件。\n<<<\nprint "Hello\sn" while false\nbegin\n print "Goodbye\sn"\nend while false\n<<<\n \nproduces: Goodbye\n \n
! 操作表达式(Operator Expressions)\nRuby提供了诸如加减乘除等一些操作符,完整的操作符列表和优先级在第18章有列表。\n\n在Ruby中,很多操作符就是对一些方法的调用。比如你执行a*b+c,实际上就是调用对象a的乘方法,把b作为一个参数传递过去,然后在调用这个结果对象的加方法,把c作为参数传递,实际上等于:\n<<<\n(a.*(b)).+(c)\n<<<\n\n因为你可以重新定义实例方法,所以你可以修改一些不能满足你的需求的方法,让它达到你需要的作用\n<<<\nclass Fixnum \n alias oldPlus + \n def +(other) \n oldPlus(other).succ \n end \nend \n \n1 + 2 » 4 \na = 3 \na += 4 » 8 \n<<<\n\n很有用的一个技巧是你自己写的的类可以像内建对象一样参与操作符的操作,比如,我们想从一首歌中间某处开始提取一部分音乐,我们可以用操作符"[ ]"来完成:\n<<<\nclass Song\n def [](fromTime, toTime)\n result = Song.new(self.title + " [extract]",\n self.artist,\n toTime - fromTime)\n result.setStartTime(fromTime)\n result\n end\nend\n<<<\n \n\n这段代码扩展了类Song,增加了[ ]方法,这个方法接收两个参数,一个开始时间,一个结束时间。这个方法返回一个新的Song对象,这个对象是歌曲的一部分。然后,我们就可以这样播放这段音乐:\n<<<\naSong[0, 0.15].play\n<<
! 数字型\n\nRuby 支持整型和浮点型两种数字类型。整型可以是任意长度(最大值由你机器的内存大小决定)。在一定范围内(通常是-230 to 230-1 or -262 to 262-1)在内部由二进制方式表示,内部类为Fixnum。大小超过这个范围的整数由Bignum表示,如果Fixnum计算之后结果超出范围,自动转换为Bignum。Ruby在两者之间自动转换,对用户来说是透明的。 \n<<<\nnum = 8\n7.[[times]] do\n //print num.[[type]], " ", num, "\sn"\n print num.[[class]], " ", num, "\sn"\n num *= num\nend\n<<<\n \nproduces: Fixnum 8\nFixnum 64\nFixnum 4096\nFixnum 16777216\nBignum 281474976710656\nBignum 79228162514264337593543950336\nBignum 6277101735386680763835789423207666416102355444464034512896\n\n你也可以在使用整型的时候在前面使用进制标示符,比如0表示八进制,0x表示十六进制,0b表示二进制等。而且,如果一个整型数字中有一个下划线,这个下划线将被忽略。\n\n<<<\n123456 # Fixnum\n123_456 # Fixnum (underscore ignored)\n-543 # Negative Fixnum\n123_456_789_123_345_789 # Bignum\n0xaabb # Hexadecimal\n0377 # Octal\n-0b101_010 # Binary (negated)\n<<<\n\n你也可以得到一个ASCII字符或者一个转义字符的数字值通过在它前面加一个问号。Control和Meta键的组合也可以用?\sC-x, ?\sM-x 和 ?\sM-\sC-x表达。字符value的加Control键的版本和"value & 0x9f"的值是一样的;字符value的加Meta键的版本和"value & 0x80"的值是一样的。最后,序列 ?\sC-? 产生一个ASCII码的删除,0177。\n\n<<<\n?a # 字符的数字值\n?\sn # 换行符的值 (0x0a)\n?\sC-a # control a = ?A & 0x9f = 0x01\n?\sM-a # meta sets bit 7\n?\sM-\sC-a # meta 和 control a\n?\sC-? # 删除字符\n<<<\n\n一个带小数点或者带指数的数字字符串会转换成一个Float对象,对应于本机操作系统构架的double数据类型。你必须在小数点后面加一个数字,因为像 1.e3会认为是调用了Fixnum类的e3这个方法。\n\n所有数字都是对象,会响应一些消息(在290, 313, 315, 323和349页会完整的描述)。所以不像(比如说) C++,你会发现求一个数字的绝对值是这样写的 aNumber.abs,而不是abs(aNumber)。\n整数也支持一些有用的迭代器(iterators)。我们已经看到过一个了--- 7.times在47页的代码例子中。还有其他的比如 upto 和 downto,用来在两个整数之间向上和向下迭代,还有 step,用于传统的 for 循环语句。 \n\n<<<\n3.times { print "X " }\n1.upto(5) { |i| print i, " " }\n99.downto(95) { |i| print i, " " }\n50.step(80, 5) { |i| print i, " " }\n<<<\n \n会产生: X X X 1 2 3 4 5 99 98 97 96 95 50 55 60 65 70 75 80\n\n最后,给Perl使用者提供一个警告。含有数字字符的字符串在表达式中使用时不会自动转换成数字。这最有可能在从文件里读取数字时引发错误。下面的代码没有做我们 想要的。\n<<<\nDATA.each do |line|\n vals = line.split #分割一行,把值存在vals里面\n print vals[0] + vals[1], " "\nend\n<<<\n给它一个文件,内容是:\n\n3 4\n5 6\n7 8\n\n你会得到结果: ``34 56 78.'' 到底发生了什么呢? \n\n问题就出在程序把输入当成字符串,而不是数字的。加号运算符把两个字符串连接,这就是我们看到这个结果的原因。要解决这个问题,我们可以使用String#to_i这个方法来把字符串转换成整数。\n<<<\nDATA.each do |line|\n vals = line.split\n print vals[0].to_i + vals[1].to_i, " "\nend\n<<<\n \n得到结果: 7 11 15\n\n \n
Ruby有几种不同的机制来实现条件执行,大多数都感觉很类似,也有一些很灵巧,在深入讨论之前,我们先来花点时间看看布尔表达式。\n\n! Boolean 表达式\nRuby中的true定义很简单,任何不是nil和false常量的东西都是true,你会发现系统的实现库中很多这种用法。比如,IO#gets ,用来返回一个文件的下一行,如果到了文件末尾,返回nil,所以,我们才可以这样通过while来循环读取数据:\n<<<\nwhile line = gets\n # process line\nend\n<<<\n\n但是,这里对于c和perl程序员来说有一个误区,数字0和长度为0的字符串都不会被解释成false值,需要注意。\n\n! Defined?, And, Or, 和 Not\nRuby支持所有标准的布尔操作,另外,还引入了新的操作符defined?\n\n操作符``and'' 和``&&'' 只有当两面的值都为真才会返回真,第一个值为真,才会判断第二个值,否则直接返回假。这两个操作符的区别是优先级不同(and低于 &&)\n\n类似的 ``or'' 和``||''有一方为真就会返回真,如果第一个为真,则不会判断后面的值,类似and,这两个操作符只有优先级的不同。\n\nand和or有相同的优先级,而&&的优先级高于||。\n\n \n``not'' and ``!'' 返回操作数的相反的值,如果操作数为true,则这个操作符返回false。并且and和!也只是优先级不同。 \n所有的这些操作符和优先级都在18章有详细讲述。\n\n操作符defined?将返回nil,如果操作数没有定义的话。否则,将返回后面参数的描述信息。\n\n<<<\ndefined? 1 » "expression" \ndefined? dummy » nil \ndefined? printf » "method" \ndefined? String » "constant" \ndefined? $& » nil \ndefined? $_ » "global-variable" \ndefined? Math::PI » "constant" \ndefined? ( c,d = 1,2 ) » "assignment" \ndefined? 42.abs » "method" \n<<<\n\n除了这些布尔表达式,Ruby对象还支持使用 ==, ===, <=>, =~, eql?, 和equal?进行对象之间的比较。除了<=>之外这些操作符都在Object类中定义,但是经常被子类重载。比如,类Array重定义了==方法,判断两个数组相同的条件事它们的个数相同,同一位置的元素也相同。\n\n>>>\n通用比较操作符 \n操作符 意义 \n== 测试是否相同 \n=== 在case中的when语句判断是否相等 \n<=> 通用比较操作符,根据前面的对象小于,等于还是大于后面的对象,返回 -1, 0, 或者 +1。 \n<, <=, >=, > 小于,小于等于,大于等于,大于 \n=~ 正则表达式匹配 \neql? 如果前后两个对象都是同一类型,则返回true: 1 == 1.0返回true但是 1.eql?(1.0) 结果为false。 \nequal? 只有两个对象有相同的object id 才返回true。 \n>>>\n\n==和=~都有相反的操作符!=和!~,但是Ruby会将程序中的a!=b转换为!(a==b),a!~b转换成!(a=~b),如果你自己的类中重新写了==和=~方法,那么你同时的到了!=和!~两个方法;同时,你也不能离开了==和=~而孤立的定义!=和!~两个方法。\n\n你可以使用Ruby range 作为一个布尔表达式,一个类似 exp1..exp2 的range只有在遇到exp1为true,然后exp2又为true之后,才会返回true。下面循环部分有例子。 \n最后,你可以用正则表达式来当作一个布尔表达式。Ruby expands it to $_=~/re/.\n\n! If 和 Unless表达式\n\nRuby中的if语句跟其他语言类似。\n<<<\nif aSong.artist == "Gillespie" then\n handle = "Dizzy"\nelsif aSong.artist == "Parker" then\n handle = "Bird"\nelse\n handle = "unknown"\nend\n<<<\n \n\n__如果你的if语句写在多行上,可以省略then关键字。__\n<<<\nif aSong.artist == "Gillespie"\n handle = "Dizzy"\nelsif aSong.artist == "Parker"\n handle = "Bird"\nelse\n handle = "unknown"\nend\n<<<\n \n\n但是,__如果你的语句都写在一行上,then应该写上来分开布尔表达式和后面的语句。__\n<<<\nif aSong.artist == "Gillespie" then handle = "Dizzy"\nelsif aSong.artist == "Parker" then handle = "Bird"\nelse handle = "unknown"\nend\n<<<\n \n\n你可以使用0个或多个elsif语句,和一个可选的else语句。\n\n就像我们前面说道的,if是一个表达式,不是一个statement,它可以返回一个值,你不必使用if表达式的返回值,但是它可能有些用处。\n\n<<<\nhandle = if aSong.artist == "Gillespie" then\n "Dizzy"\n elsif aSong.artist == "Parker" then\n "Bird"\n else\n "unknown"\n end\n<<<\n\nRuby也为if提供了一个否定的形式,unless: \n<<<\nunless aSong.duration > 180 then\n cost = .25\nelse\n cost = .35\nend\n<<<\n \n最后,也为使用C语言的程序员准备了条件表达式:\n\n<<<\ncost = aSong.duration > 180 ? .35 : .25\n<<<\n \n\n这个条件表达式在根据?前面的布尔值为true或false返回冒号前面或后面的值。在这个例子中,如果歌曲的时长大于3分钟,将返回.35,否则返回.25,然后,将这个值赋给cost。\n\nIf 和 Unless 修饰符(Modifiers)\nRuby也借鉴了Perl的一些特点,语句修饰符(Statement modifiers)使我们可以在语句末尾加上条件语句。\n\n<<<\nmon, day, year = $1, $2, $3 if /(\sd\sd)-(\sd\sd)-(\sd\sd)/\nputs "a = #{a}" if fDebug\nprint total unless total == 0\n<<<\n \n\n对于if修饰符来说,只有当if后面的条件为true,前面的语句才会执行,unless正好和if相反。\n\n<<<\nwhile gets\n next if /^#/ # Skip comments\n parseLine unless /^$/ # Don't parse empty lines\nend\n<<<\n \n\n因为if本身也是表达式,所以下面的写法将会使代码变得难懂。\n\n<<<\nif artist == "John Coltrane"\n artist = "'Trane"\nend unless nicknames == "no"\n<<<\n \n
*[[数字型]]\n*[[字符串]]\n*[[运用字符串]]\n*[[范围]]\n*[[正则表达式]]
==回到第50页当我们从一个文件里创建歌曲列表的时候,我们用了一个正则表达式去匹配文件里的字段。我们声明了正则表达式 line.split(/\ss*|\ss*)来匹配一个小竖线被(不是必须的)空格环绕的情况。让我们来仔细研究一下正则表达式来证明为什么我们的声明是正确的。==\n正则表达式用来匹配字符串的模式。Ruby提供了对模式匹配和替换内建的支持,使我们使用时很方便简练。在这部分,我们会介绍大部分主要的正则表达式特征。==有些细节我们不会涉及:你可以参考第205页取得更多信息。==\n\n\n正则表达式是类型Regexp的对象。它们可以用显式的构造函数建立或者直接用 /pattern/ 和 %r/pattern/这种格式的字符常量构造。\n<<<\na = Regexp.new('^\ss*[a-z]') }} /^\ss*[a-z]/ \nb = /^\ss*[a-z]/ }} /^\ss*[a-z]/ \nc = %r{^\ss*[a-z]} }} /^\ss*[a-z]/ \n<<<\n\n一当你有了一个正则表达式对象,你可以用它和一个字符串比较,通过使用 Regexp#match(aString) 或者用匹配操作符 =~(确定匹配)和 !~(否定匹配)。字符串和Regexp对象都可以使用匹配操作符。@@如果匹配操作符的两个操作数都是字符串的话,右边那个会转化成正则表达式。@@\n<<<\na = "Fats Waller" \na =~ /a/ }} 1 \na =~ /z/ }} nil \na =~ "ll" }} 7 \n<<<\n\n匹配操作符返回模式匹配成功的字符位置。 它们还有一个设置所有Ruby变量的额外作用。$&接受模式匹配成功的那部分字符,$`(键盘1左边那个键)接受模式匹配成功前面那一部分字符,$'接受模式匹配成功后面那部分字符。我们可以用这个来编写一个函数,showRE,它阐明了一个特殊的模式匹配例子:\n<<<\ndef showRE(a,re) \n if a =~ re \n "#{$`}<<#{$&}>>#{$'}" \n else \n "no match" \n end \nend \n \nshowRE('very interesting', /t/) }} very in<<t>>eresting \nshowRE('Fats Waller', /ll/) }} Fats Wa<<ll>>er \n<<<\n\n\n这个匹配也设置了Ruby的全局线程(thread-global)变量 $~ 和 $1 到 $9。变量 $~ 是一个MatchData对象(在336页开始部分有描述),它保存了所有关于这个匹配的信息。$1和其他$*保存了这个匹配的部分,我们呆会儿还会讨论它们。如果有人看见这些像Perl语言的变量名感到害怕,不要着急,这章后面还有好消息。 \n\n! 模式(Patterns)\n\n每个正则表达式都有一个模式,用来和字符串做匹配。\n在一个模式中,除了., |, (, ), [, {, +, \s, ^, $, *和 ? 之外的字符都是和它本身匹配。 \n<<<\nshowRE('kangaroo', /angar/) }} k<<angar>>oo \nshowRE('!@%&-_=+', /%&/) }} !@<<%&>>-_=+ \n<<<\n\n\n如果你想在字面上匹配一个上面的特殊字符,在它前面加一个'\s'。这解释了我们用在分离那个歌曲列表文件时用的一个正则表达式的一部分,/\ss*|\ss*/。'\s|'表示匹配一个'|',没有那个反斜杠,'|'代表交换(我们会在后面描述)。 \n<<<\nshowRE('yes | no', /\s|/) }} yes <<|>> no \nshowRE('yes (no)', /\s(no\s)/) }} yes <<(no)>> \nshowRE('are you sure?', /e\s?/) }} are you sur<<e?>> \n<<<\n\n\n反斜杠后跟一个数字字符用来引进一个特殊的匹配构造,我们会在后面介绍它。另外,一个正则表达式可以包含#{...}表达式取代。\nAnchors\n\n一个正则表达式默认会找到字符串中第一个匹配的情况。要在字符串"Mississippi"中匹配 /iss/ ,它会找到那个靠近开始位置的哪个子串"iss"。但是当你想自己指定从头部或者末尾开始匹配时要怎么设置呢?\n\n模式 ^ 和 $ 分别匹配一行字符的开始和结束。它们经常用来指定一个模式匹配的方向:比如,/^option/和在一行文本开始处出现的字符串'option'匹配。字符序列 \sA 和一个字符串的开始匹配,\sz 和 \sZ 和一个字符串的结束匹配。(事实上,\sZ 和一个以"\sn"结尾的字符串的结束匹配,这种情况下,它从'\sn'前面开始匹配)。\n<<<\nshowRE("this is\snthe time", /^the/) }} this is\sn<<the>> time \nshowRE("this is\snthe time", /is$/) }} this <<is>>\snthe time \nshowRE("this is\snthe time", /\sAthis/) }} <<this>> is\snthe time \nshowRE("this is\snthe time", /\sAthe/) }} no match \n<<<\n\n相似的,模式 \sb 和 \sB 分别和单词界限(word boundaries)和非单词界限(nonword boundaries)匹配。构成单词的字符有字母,数字和下划线。 \n<<<\nshowRE("this is\snthe time", /\sbis/) }} this <<is>>\snthe time \nshowRE("this is\snthe time", /\sBis/) }} th<<is>> is\snthe time \n<<<\n\n! 字符类(character class)\n\n一个字符类是一系列在方括号("[...]")之间的字符,用来匹配方括号里面的单个字符。比如,[aeiou]会和元音字符匹配,[,.:;!?]和标点符号匹配,等等。那些重要的特殊字符(.|()[{+^$*?)在方括号里面会失去匹配作用。但是普通的转义字符仍然起作用,所以,\sb代表退格键,\sn是换行符(见203页表18.2)。另外,你可以用59页的表5.1的缩写,所以 \ss 表示空白符,不仅仅是一个字面上的空格。\n<<<\nshowRE('It costs $12.', /[aeiou]/) }} It c<<o>>sts $12. \nshowRE('It costs $12.', /[\ss]/) }} It<< >>costs $12. \n<<<\n\n在方括号里面,序列 c1-c2 表示包括在c1到c2之间的字符。\n如果你想在字符类(方括号)里面包含 ] 和 - 的话,它们必须出现在开始。 \n\n<<<\na = 'Gamma [Design Patterns-page 123]' \nshowRE(a, /[]]/) }} Gamma [Design Patterns-page 123<<]>> \nshowRE(a, /[B-F]/) }} Gamma [<<D>>esign Patterns-page 123] \nshowRE(a, /[-]/) }} Gamma [Design Patterns<<->>page 123] \nshowRE(a, /[0-9]/) }} Gamma [Design Patterns-page <<1>>23] \n<<<\n\n在'['后面紧跟一个 ^ 代表字符类相反的含义: [^a-z]和不是小写字母的字符匹配。\n\n一些字符类特别常用,所以Ruby提供了它们的缩写形式。这些缩写列在59页的表5.1上,它们可以用在方括号和模式串里面。 \n<<<\nshowRE('It costs $12.', /\ss/) }} It<< >>costs $12. \nshowRE('It costs $12.', /\sd/) }} It costs $<<1>>2. \n<<<\n\n字符类缩写 字符序列 [ ... ] 意思 \n<<<\n\sd [0-9] 数字字符 \n\sD [^0-9] 非数字 \n\ss [\ss\st\sr\sn\sf] 空格字符 \n\sS [^\ss\st\sr\sn\sf] 非空格字符 \n\sw [A-Za-z0-9_] 单词符号 \n\sW [^A-Za-z0-9_] 非单词符号 \n<<<\n\n最后,一个在放括号外面出现的句点"."表示除了换行符以外的任何字符(在多行模式下它也表示一个换行符)。\n<<<\na = 'It costs $12.' \nshowRE(a, /c.s/) }} It <<cos>>ts $12. \nshowRE(a, /./) }} <<I>>t costs $12. \nshowRE(a, /\s./) }} It costs $12<<.>> \n<<<\n\n! 重复(Repetition)\n\n在我们讲述那个分隔歌曲文件的正则模式(/\ss*\s|\ss*/)的时候, 我们说想匹配在一个'|'两边环绕任意的空格的情况。现在我们知道了 \ss 匹配一个空白符,所以看来星号'*'代表任意数的大小。事实上,星号是允许你匹配模式多次出现的修饰符中的一个。\n\n如果 r 代表一个模式里面的前置字符,那么:r * 匹配0个或多个 r. \n<<<\nr + 匹配1个或多个 r. \nr ? 匹配0个或1个 r. \nr {m,n} 匹配最少m个,最多n个 r. \nr {m,} 匹配最少m个 r. \n<<<\n\n这些重复修饰符有很高的优先权---在正则模式串里它们仅仅和它们的紧密前缀绑定。/ab+/匹配一个"a"后面跟一个或多个"b"而不是一个"ab"组成的序列。你也必须小心使用'*'修饰符---正则模式串/a*/会匹配任何字符串;任何有0个或者多个"a"的字符串。\n\n这些模式串被称为“贪婪地”,因为它们默认会匹配尽量多的字符。你可以改变这种行为,让它们匹配最少的,只要加一个问号后缀就可以了。\n<<<\na = "The moon is made of cheese" \nshowRE(a, /\sw+/) }} <<The>> moon is made of cheese \nshowRE(a, /\ss.*\ss/) }} The<< moon is made of >>cheese \nshowRE(a, /\ss.*?\ss/) }} The<< moon >>is made of cheese \nshowRE(a, /[aeiou]{2,99}/) }} The m<<oo>>n is made of cheese \nshowRE(a, /mo?o/) }} The <<moo>>n is made of cheese \n<<<\n\n! 间隔(Alternation)\n\n我们知道‘|’是特殊的,因为我们的在行分隔模式中必须用一个反斜杠使之转义。因为一个没有反斜杠的‘|’匹配正则表达式中它左右两边模式中的一个。\n<<<\na = "red ball blue sky" \nshowRE(a, /d|e/) }} r<<e>>d ball blue sky \nshowRE(a, /al|lu/) }} red b<<al>>l blue sky \nshowRE(a, /red ball|angry sky/) }} <<red ball>> blue sky \n<<<\n\n要是我们一粗心,这里会有一个陷阱,因为‘|’的优先级很低。在上面最后一个例子中,我们的正则式匹配“red ball”或者“angry sky”,而不是“red ball sky”或“red angry sky”。为了匹配“red ball sky”或“red angry sky”,我们用grouping重载默认的优先级。\n成组技术(Grouping)\n\n你可以在正则式中用圆括号来成组字符集。在这个组里面的所有字符会被认为是一个正则表达式。\n<<<\nshowRE('banana', /an*/) }} b<<an>>ana \nshowRE('banana', /(an)*/) }} <<>>banana \nshowRE('banana', /(an)+/) }} b<<anan>>a \n\na = 'red ball blue sky' \nshowRE(a, /blue|red/) }} <<red>> ball blue sky \nshowRE(a, /(blue|red) \sw+/) }} <<red ball>> blue sky \nshowRE(a, /(red|blue) \sw+/) }} <<red ball>> blue sky \nshowRE(a, /red|blue \sw+/) }} <<red>> ball blue sky \n\nshowRE(a, /red (ball|angry) sky/) }} no match \na = 'the red angry sky' \nshowRE(a, /red (ball|angry) sky/) }} the <<red angry sky>> \n<<<\n\n圆括号也用来收集模式匹配的结果。Ruby对左括号记数,对每个左括号,它保存了已经匹配的部分结果和相应的右括号。你可以在剩下的模式串中或者你的Ruby程序里使用这个匹配。在模式匹配中,\s1代表第1个组,\s2代表第2个组,其他依次类推。在模式串外面,特殊变量 $1, $2和其他$*和这个作用一样。\n<<<\n"12:50am" =~ /(\sd\sd):(\sd\sd)(..)/ }} 0 \n"Hour is #$1, minute #$2" }} "Hour is 12, minute 50" \n"12:50am" =~ /((\sd\sd):(\sd\sd))(..)/ }} 0 \n"Time is #$1" }} "Time is 12:50" \n"Hour is #$2, minute #$3" }} "Hour is 12, minute 50" \n"AM/PM is #$4" }} "AM/PM is am" \n<<<\n\n能够利用目前的部分匹配允许你寻找各种形式的循环。 \n<<<\n# 匹配重复的字母 \nshowRE('He said "Hello"', /(\sw)\s1/) }} He said "He<<ll>>o" \n# 匹配重复的子串 \nshowRE('Mississippi', /(\sw+)\s1/) }} M<<ississ>>ippi \n<<<\n\n\n你也可以使用后置引用来匹配分隔符。\n<<<\nshowRE('He said "Hello"', /(["']).*?\s1/) }} He said <<"Hello">> \nshowRE("He said 'Hello'", /(["']).*?\s1/) }} He said <<'Hello'>> \n<<<\n\n! 基于模式的子串技术\n\n有时候在一个字符串里面寻找一个模式已经满足要求了。如果一个朋友刁难你,要你找出一个顺序包含a, b, c, d 和 e 的单词,你可以用模式串 /a.*b.*c.*d.*e/来寻找然后可以找到"absconded"和"ambuscade" 。这毫无疑问是挺有用的。\n然后,有时候我们需要改变一个模式匹配的内容。让我们回到我们的歌曲列表文件。创建文件的人用小写字母敲进了演唱者的名字。当我们把名字显示在点唱机上时,我们想让它大小写混写。那么我们怎么样才能把每个单词的首字母变成大写呢?\n\nString#sub 和 String#gsub 方法 寻找字符串中匹配它们第一个参数的那部分,然后把那部分用它们的第二个参数代替。String#sub 只替换一次,String#gsub 则替换所有在字符串里出现的匹配。两个方法都返回一个已经替换过的新字符串的拷贝。另外一个版本的方法String#sub! 和 String#gsub! 会修改原始字符串。\n<<<\na = "the quick brown fox" \na.sub(/[aeiou]/, '*') }} "th* quick brown fox" \na.gsub(/[aeiou]/, '*') }} "th* q**ck br*wn f*x" \na.sub(/\ss\sS+/, '') }} "the brown fox" \na.gsub(/\ss\sS+/, '') }} "the" \n<<<\n\n第二个参数可以是一个字符串或者一个程序块(block)。如果用了程序块,那个程序块的值被替换进了字符串。\n\na = "the quick brown fox" \na.sub(/^./) { $&.upcase } }} "The quick brown fox" \na.gsub(/[aeiou]/) { $&.upcase } }} "thE qUIck brOwn fOx" \n\n所以,这看起来是我们转变演唱者名字的正确方法。匹配一个单词的首字母的模式串是 \sb\sw---寻找一个单词边界然后跟一个字母。结合 gsub 使用,我们可以来修改演唱者的名字了。 \n<<<\ndef mixedCase(aName) \n aName.gsub(/\sb\sw/) { $&.upcase } \nend \n \nmixedCase("fats waller") }} "Fats Waller" \nmixedCase("louis armstrong") }} "Louis Armstrong" \nmixedCase("strength in numbers") }} "Strength In Numbers" \n<<<\n\n! 子串函数中的转义字符\n\n前面我们讲过\s1, \s2和类似的字符序列可以在模式串中使用,代表到现在为止已经匹配的第n组数据。相同的字符序列也可以在 sub 和 gsub函数的第二个参数中使用。\n\n<<<\n"fred:smith".sub(/(\sw+):(\sw+)/, '\s2, \s1') }} "smith, fred" \n"nercpyitno".gsub(/(.)(.)/, '\s2\s1') }} "encryption" \n<<<\n\n\n还有一些外加的转义字符用在字符串替换中:\s&(最后那个匹配),\s+(最后匹配的组),\s`(匹配串前面的字符串),\s'(匹配后面的字符串),\s\s(反斜杠)。如果你在替换中使用反斜杠那么会引起混乱。最明显的例子是:\n<<<\nstr.gsub(/\s\s/, '\s\s\s\s')\n<<<\n \n很清楚,这句代码想把 str 里面的一个反斜杠变成两个。程序员用了两个反斜杠在替换文本里面,希望它们在语法分析时变成两个反斜杠。但是当替换发生时,正则表达式引擎又读了一遍字符串,把"\s\s"变成了"\s",所以上面代码的作用是用一个反斜杠替换另外一个反斜杠。你需要这样写 gsub(/\s\s/, '\s\s\s\s\s\s\s\s')! \n<<<\nstr = 'a\sb\sc' }} "a\sb\sc" \nstr.gsub(/\s\s/, '\s\s\s\s\s\s\s\s') }} "a\s\sb\s\sc" \n<<<\n\n因为 \s& 会被匹配的字符串替换,所以你也可以这样写:\n<<<\nstr = 'a\sb\sc' }} "a\sb\sc" \nstr.gsub(/\s\s/, '\s&\s&') }} "a\s\sb\s\sc" \n<<<\n\n如果你使用 gsub 的程序块形式,用来替换的字符串仅仅被分析一次(在语法分析阶段),所以结果是你想要的:\n<<<\nstr = 'a\sb\sc' }} "a\sb\sc" \nstr.gsub(/\s\s/) { '\s\s\s\s' } }} "a\s\sb\s\sc" \n<<<\n\n最后,作为正则表达式和程序块结合起来的强大表现力的例子,我们来看看这段CGI函数库模块里的代码,是Wakou Aoyama编写的。代码接受一段包含HTML文本的字符串然后把它转化成普通的ASCII文本。因为这是为日本的用户编写的,它在正则式用了"n"修饰符来使宽字符失效。代码也演示了Ruby的 case 语句,我们在81页讨论它。\n<<<\ndef unescapeHTML(string)\n str = string.dup\n str.gsub!(/&(.*?);/n) {\n match = $1.dup\n case match\n when /\sAamp\sz/ni then '&'\n when /\sAquot\sz/ni then '"'\n when /\sAgt\sz/ni then '>'\n when /\sAlt\sz/ni then '<'\n when /\sA#(\sd+)\sz/n then Integer($1).chr\n when /\sA#x([0-9a-f]+)\sz/ni then $1.hex.chr\n end\n }\n str\nend\n \nputs unescapeHTML("1<2 && 4>3") \nputs unescapeHTML(""A" = A = A")\n<<<\n \n产生结果: 1<2 && 4>3\n"A" = A = A\n\n! 面向对象的正则表达式\n\n我们必须承认虽然这些古怪的表达式很好用,但是它们不是面向对象的,而且相当晦涩难懂。你们不是说过Ruby里面任何东西都是对象吗?为什么这里是这样的呢?\n\n这无关紧要,真的。因为Matz在设计Ruby的时候,他构建了一个完全面向对象的正则表达式处理系统。但是为了让Perl程序员感到熟悉一些,他把这些 $* 包装在这系统之上。这些对象和类还在那里,在外观里面,现在让我们花点时间把它们挖出来。\n\n我们已经遇到过这样一个类了:字面正则表达式的产生类 [[Regexp]](在361页有具体描述)。\n<<<\nre = /cat/ \nre.type }} Regexp \n<<<\n\n__方法 [[Regexp#match]] 把一个正则表达式和一个字符串进行匹配。__如果不成功,方法返回 nil。在成功的情况下,它返回类 Matchdata 的一个实例,在336页有详细描述。然后那个 MatchData 对象给你访问这个匹配的各种信息的方法。所有能从 $-*变量里得到的好东东都可以在咱们手边这个小对象里得到。\n<<<\nre = /(\sd+):(\sd+)/ # 匹配一个时间 hh:mm \nmd = re.match("Time: 12:34am") \nmd.type => MatchData \nmd[0] # = = $& => "12:34" \nmd[1] # = = $1 => "12" \nmd[2] # = = $2 => "34" \nmd.pre_match # = = $` => "Time: " \nmd.post_match # = = $' => "am" \n<<<\n\n因为匹配信息是保存在它自己对象里的,你可以在同一时间保存两个或者多个匹配的结果,这用$-*你可能不能实现。在下面一个例子里,我们用同一个 Regexp 对象去匹配两个不同的字符串。每个匹配都返回一个唯一的 MatchData 对象,我们通过它们的两个子模式字段来区别它们。 \n\n<<<\nre = /(\sd+):(\sd+)/ # 匹配一个时间 hh:mm \nmd1 = re.match("Time: 12:34am") \nmd2 = re.match("Time: 10:30pm") \nmd1[1, 2] => ["12", "34"] \nmd2[1, 2] => ["10", "30"] \n<<<\n\n但是那些 $-*是怎么包装起来的呢?每个模式匹配结束以后,Ruby在一个局部线程(thread-local)变量中保存了一个指向结果的引用(nil 或者 是一个 MatchData 对象)。所有其他的正则表达式变量都是从这个对象中继承而来的。虽然我们不能真正这样使用以下代码,但是它证明了所有其他的和MatchData有关的 $-*变量都是 $~里面的值。\n\n<<<\nre = /(\sd+):(\sd+)/ \nmd1 = re.match("Time: 12:34am") \nmd2 = re.match("Time: 10:30pm") \n[ $1, $2 ] # 最后匹配成功的情况 => ["10", "30"] \n$~ = md1 \n[ $1, $2 ] # 上一个匹配成功情况 => ["12", "34"] \n<<<\n\n\n说完了所有这些,我们必须说点实话:) Andy和Dave平常都只是使用$-*变量而不去担心 MatchData对象。在日常应用中,我们只要用起来舒服就行。有时候我们情不自禁地使自己变得更务实。
一些其它语言有函数,过程,方法等,而Ruby中只有方法:一段表达式代码,返回一个值。\n\n到目前为止,我们在这本书中只是基本的介绍了如何定义,使用方法,现在,我们会继续深入的探讨一些关于方法更深层的东西。\n\n! 方法定义\n如同在前面看到的一样,定义一个方法用关键字def开头,方法名应该以小写字母开头[如果你用大写字母开头定义一个方法,你不会立即得到一个错误,但是当你调用这个方法时,Ruby首先认为你访问的是一个常量,所以可能会解析错误],如果一个方法主要用来完成一些查询操作(不专指数据库查询),通常以一个问号"?"结束,作为函数名的最后一个字母,比如instance_of?等。如果一个方法有一定危险,或者可能修改方法的接受者,通常以"!"结尾,比如String类提供了chop和chop!两个方法,第一个方法返回一个修改过的字符串,而第二个方法直接就修改了接收者本身。"?"和"!"是唯一两个能作为方法名后缀的特殊字符。\n\n我们已经指定了方法名,如果需要,我们可以定义一些参数,这些参数用双括号括起来,作用域范围都是局部变量,一些例子如下:\n<<<\ndef myNewMethod(arg1, arg2, arg3) # 3 arguments\n # Code for the method would go here\nend\n\ndef myOtherNewMethod # No arguments \n # Code for the method would go here \nend\n<<<\n\nRuby允许为方法的参数设置默认值:如果调用者没有显示的为这些参数提供值,将使用这些默认值。通过"=",就可以为这些参数设定默认值。\n<<<\ndef coolDude(arg1="Miles", arg2="Coltrane", arg3="Roach") \n "#{arg1}, #{arg2}, #{arg3}." \nend \n \ncoolDude » "Miles, Coltrane, Roach." \ncoolDude("Bart") » "Bart, Coltrane, Roach." \ncoolDude("Bart", "Elwood") » "Bart, Elwood, Roach." \ncoolDude("Bart", "Elwood", "Linus") » "Bart, Elwood, Linus." \n<<<\n方法体中包含了一般的Ruby表达式,但是你不能在方法里面定义实例方法,类或者模块。方法的返回值是方法体最后一行执行后的结果,或者你显示的用一个return语句。\n\n\n可变长度的参数列表\n如果我们想给方法传入一个数目不定的参数,或者把所有参数放到一个参数中进行传递的话,该怎么办呢?我们可以在普通的参数后面加入一个特殊的参数,这个参数以"*"开头,就可以达到这个目的了。\n<<<\ndef varargs(arg1, *rest) \n "Got #{arg1} and #{rest.join(', ')}" \nend \n \nvarargs("one") » "Got one and " \nvarargs("one", "two") » "Got one and two" \nvarargs "one", "two", "three" » "Got one and two, three" \n<<<\n在这个例子中,第一个参数很普通,直接作为第一个参数变量,而后面以"*"开头的参数,将会包括调用时候后面的所有参数,是一个Array的结构,包括了从第二个开始的所有参数。\n\n方法和块\n在讨论块和迭代的那章时,我们知道,当一个方法被调用时候,可以接收一个block,而我们在方法中可以用yield来执行这个block。\n<html>\n<pre>\ndef takeBlock(p1)\n if block_given?\n yield(p1)\n else\n p1\n end\nend\n\ntakeBlock("no block") » "no block" \ntakeBlock("no block") { |s| s.sub(/no /, '') } » "block"\n</pre>\n</html>\n\n但是,当方法接受参数中最后一个参数以"&"开始的时候,任何给定的block都会转换为Proc对象,并且这个Proc对象将会赋值给这个参数(下例中block指向一个Proc对象)。\n\n<<<\nclass TaxCalculator \n def initialize(name, &block) \n @name, @block = name, block \n end \n def getTax(amount) \n "#@name on #{amount} = #{ @block.call(amount) }" \n end \nend \n \ntc = TaxCalculator.new("Sales tax") { |amt| amt * 0.075 } \n \ntc.getTax(100) » "Sales tax on 100 = 7.5" \ntc.getTax(250) » "Sales tax on 250 = 18.75" \n<<<\n\n! 调用方法\n通常,调用一个方法需要指定一个接收者,方法名,还有一些参数或者block。\n<<<\nconnection.downloadMP3("jitterbug") { |p| showProgress(p) }\n<<<\n \n在这个例子里,connection是接收者,downloadMP3是方法名,"jitterbug"是一个参数,{ |p| showProgress(p) }是传递给这个方法的块。\n\n对于类或者模块方法来说,接收者是类或模块名:\n<<<\nFile.size("testfile")\nMath.sin(Math::PI/4)\n<<<\n\n如果你省略了接收者,那么默认为self是接收者,即当前对象:\n<<<\nself.id » 537794160 \nid » 537794160 \nself.type » Object \ntype » Object \n<<<\n这种机制也是Ruby实现private方法的体现,private方法不能用一个接收者来直接调用,只能在当前对象中使用。\n\n 方法名后面是可选的参数,如果不会出现歧义的话,调用方法时参数可以不加括号括起来[Ruby文档有时候也叫做这样的方法是命令(commands)],然而,除非特别简单的方法,否则还是加上括号的好,要不可能容易出错,比如,你的方法嵌套在另一个方法调用之中。\n<<<\na = obj.hash # Same as\na = obj.hash() # this.\n\nobj.someMethod "Arg1", arg2, arg3 # Same thing as \nobj.someMethod("Arg1", arg2, arg3) # with parentheses.\n<<<\n \n\n! 在方法调用时使用数组\n前面我们已经说过了,在一个方法的参数前面可以加一个星号,这样所有后面的参数都被放到了一个数组中,反过来,Ruby也支持调用的时候指定一个数组代替若干个参数。\n\n在调用方法的时候,你可以使用一个数组作为一个参数,它的每个元素都将作为一个单独的参数使用。使用的时候,需要在这个作为参数的数组前面加一个星号。\n<<<\ndef five(a, b, c, d, e) \n "I was passed #{a} #{b} #{c} #{d} #{e}" \nend \n \nfive(1, 2, 3, 4, 5 ) » "I was passed 1 2 3 4 5" \nfive(1, 2, 3, *['a', 'b']) » "I was passed 1 2 3 a b" \nfive(*(10..14).to_a) » "I was passed 10 11 12 13 14" \n<<<\n\n! 更加动态的block\n\n我们已经看过了如何把一个方法和一个块联系起来。\n<<<\nlistBones("aardvark") do |aBone|\n # ...\nend\n<<<\n \n\n通常,这已经足够好了,我们可以给一个方法提供一个机构良好的块,而不必再方法中使用很多的if或者while等语句。\n\n 但是有些时候,你需要更灵活一些,比如,下面的例子,如果选择times,即输入t,将会打印2,4,6,8等等:\n\n<<<\nprint "(t)imes or (p)lus: "\ntimes = gets\nprint "number: "\nnumber = gets.to_i\n\nif times =~ /^t/ \n puts((1..10).collect { |n| n*number }.join(", ")) \nelse \n puts((1..10).collect { |n| n+number }.join(", ")) \nend\n<<<\n \n结果: (t)imes or (p)lus: t\nnumber: 2\n2, 4, 6, 8, 10, 12, 14, 16, 18, 20\n\n虽然这样可以工作,但是不是很完美,我们可以把负责计算的部分抽出来组成一个block。\n\n<<<\nprint "(t)imes or (p)lus: "\ntimes = gets\nprint "number: "\nnumber = gets.to_i\n\n\nif times =~ /^t/ \n calc = proc { |n| n*number } \nelse \n calc = proc { |n| n+number } \nend \nputs((1..10).collect(&calc).join(", "))\n<<<\n \nproduces: (t)imes or (p)lus: t\nnumber: 2\n2, 4, 6, 8, 10, 12, 14, 16, 18, 20\n\n \n\n如果最后一个方法的最后一个参数以"&"开头,Ruby把它最为一个Proc来处理,传到相应的block。\n\n这种技术也有另外的用处,比如我们使用迭代器处理一些数据,把每个步骤地结果存储到一个数组中,我们下面将用到前面的Fibonacci 例子来产生一组数据: \n<<<\na = [] \nfibUpTo(20) { |val| a << val } » nil \na.inspect » "[1, 1, 2, 3, 5, 8, 13]" \n<<<\n\n尽管这样已经可以工作了,但是这显示出来的意图不像我们想象的那么明晰,所以,我们取而代之的是另外定义了一个方法into,它将返回一个完成填充array功能的block。(注意返回的block是一个闭包closure ,即使into返回了,它还指向参数anArray)\n<<<\ndef into(anArray) \n return proc { |val| anArray << val } \nend \n \nfibUpTo 20, &into(a = []) \na.inspect » "[1, 1, 2, 3, 5, 8, 13]" \n<<<\n\n! 哈希结构作为参数\n一些语言支持基于键的参数,即hash结构的参数。不按照参数的个数和位置来调用一个方法,而是用一个hash结构的键-值结构来设定参数,而不是按位置。Ruby1。6不支持这种特性,1。8支持。[本书写的是基于1.6,而目前最新的Ruby是1.8]\n\n同时,人们可以用hash结构来实现这一功能,比如,我们要为我们的SongList实现一个按名字查找的功能。 \n \n<<<\nclass SongList\n def createSearch(name, params)\n # ...\n end\nend\naList.createSearch("short jazz songs", {\n 'genre' => "jazz",\n 'durationLessThan' => 270\n } )\n<<<\n \n\n第一个参数是查找的名称,第二个参数是一个hash结构,包含了各种查找的参数。使用hash结构,我们可以是有一些键-值特性:音乐流派是jazz,时长小于4.5分钟。但是这段代码不是太好,而且大括号中的内容很容易被误认为块。所以,Ruby提供了一个快捷方式,你可以在方法的参数中指定键=>值的结构,像普通的参数那样。这样的结构都将作为一个hash结构传给方法,而不需要大扩号了。\n<<<\naList.createSearch("short jazz songs",\n 'genre' => "jazz",\n 'durationLessThan' => 270\n )\n<<<\n \n
! 混合表达式(Miscellaneous Expressions)\n除了上面最普通的操作符表达式,或者不是很显眼的语句表达式(比如if或case),Ruby还支持在表达式中使用更多的东西。\n\n! 命令展开 (Command Expansion)\n如果你用反引号(`)来括起来一个字符串,或者用%x{ 和 }括起来,那么这个表达式中的字符串默认得会作为底层的操组系统命令来执行,并返回结果,这个结果就是这个命令在操作系统中执行之后的结果。换行符将不会从结果中去掉,所以返回结果一般都会包含一个回车符。\n<<<\n`date` » "Sun Jun 9 00:08:26 CDT 2002\sn" \n`dir`.split[34] » "lib_singleton.tip" \n%x{echo "Hello there"} » "Hello there\sn" \n<<<\n你也可以在命令中使用表达式展开和所有通常的转义序列。\n<<<\nfor i in 0..3\n status = `dbmanager status id=#{i}`\n # ...\nend\n<<<\n\n执行的命令的返回状态存放在全局变量$?中。\n\n! 重载反引号方法\n上面我们说道,反引号之中的命令"默认"会作为操作系统命令来执行,实际上,这个字符串是传递给了Kernel::` 这个方法(一个反引号)来执行。如果你愿意,可以重写这个方法,比如如下:\n<<<\nalias oldBackquote `\ndef `(cmd)\n result = oldBackquote(cmd)\n if $? != 0\n raise "Command #{cmd} failed"\n end\n result\nend\nprint `date`\nprint `data`\n<<<\n \n产生: Sun Jun 9 00:08:26 CDT 2002\nprog.rb:3: command not found: data\nprog.rb:5:in ``': Command data failed (RuntimeError)\n from prog.rb:10
//{{{\nclass Song\n def [[initialize]](name,artist,duration)\n [[@]]name =name\n [[@]]artist =artist\n [[@]]duration =duration\n end\nend\n//}}}\n看看上例的成果如何:\n//{{{\naSong = Song.new("Bicylops", "Fleck", 260)\naSong.[[inspect]] }} \n"#<Song:0x401b4924 \n@duration=260, \n@artist=\s"Fleck\s", \n@name=\s"Bicylops\s">"\n//}}}\n我们的经验告诉我们,在开发过程中,我们要多次打印Song中的内容,但inspect的默认格式不能完全满足我们的要求,幸运的是,Ruby有一个标准的消息to_s,当向一个对象发送这个消息时,将会返回一个字符串,比如对于song来说:\n//{{{\naSong = Song.new("Bicylops", "Fleck", 260)\naSong.to_s }} "#<Song:0x401b499c>"\n//}}}\n这样没多少用处,甚至还不如[[inspect]],只有对象id。但是我们可以重载这个[[to_s]]方法。同时,我们也会用一点时间来说说Ruby中如何定义一个类。\n\n@@在Ruby中,类永远不会关闭,你可以一直往里面加入方法,不光是你自己写的类,系统内建的类也可以加入的。@@你需要做的是打开一个类的定义,然后就可以加入自己的方法了。\n\n这对我们来说非常好。在本章以后的例子里,我们只需要添加新的方法,老的方法还继续存在,这样省得我们花费多余的时间去在每个例子里都重写一遍。尽管我们现在写的代码比较分散,但最好还是把它们都写到一个文件中去比较好。\n\n我想已足够详细了,还是回到我们要添加的[[to_s]]方法吧。\n//{{{\nclass Song\n def to_s\n "Song: #{@name}--#{@artist} (#{@duration})"\n end\nend\naSong = Song.new("Bicylops", "Fleck", 260)\naSong.to_s }} "Song: Bicylops--Fleck (260)"\n//}}}\n非常好,我们进步了不少。但是你也许觉得被骗了,我们曾经说过Ruby中所有对象都支持to_s方法,但没有说怎么支持,答案是[[继承]]。
到目前为止我们讨论的都是实例变量和实例方法,这些变量术语每个不同的对象,用方法来操作,有时候,类也可能需要自己的状态,所以引入了类变量。 \n\n! 类变量\n\n一个类变量被所有它的实例共享,也可以被下面要提到的类方法修改。在系统中,类变量只有一个拷贝。类变量名以"@@"开头,比如"@@count"。__不像全局变量和实例变量,类变量在使用之前必须被初始化。__通常初始化只是类定义中的一条赋值语句。 \n\n比如,在我们的自动点唱机中,我们想记录一个指定的歌曲播放过多少次,这个次数应该是一个song实例变量,每当这个Song被播放,这个变量都要加1。如果,我们还想计算所有歌曲总共播放了多少次,我们可以找到所有Song对象,然后累加他们的播放次数,或者用全局变量,相反,这里我们用了类变量。 \n\n<<<\nclass Song\n @@plays = 0\n def initialize(name, artist, duration)\n @name = name\n @artist = artist\n @duration = duration\n @plays = 0\n end\n def play\n @plays += 1\n @@plays += 1\n "This song: #@plays plays. Total #@@plays plays."\n end\nend\n<<<\n \n为了调试方便, Song#play方法返回了一个字符串,显示了这首歌播放过多少次,和所有歌曲的总的播放次数。 \n<<<\ns1 = Song.new("Song1", "Artist1", 234) # test songs.. \ns2 = Song.new("Song2", "Artist2", 345) \ns1.play }} "This song: 1 plays. Total 1 plays." \ns2.play }} "This song: 1 plays. Total 2 plays." \ns1.play }} "This song: 2 plays. Total 3 plays." \ns1.play }} "This song: 3 plays. Total 4 plays." \n<<<\n\n类变量属于类和它的实例私有,如果你想在外面访问它,需要编写访问方法,既可以是实例的访问方法,也可以是下面我们要说到的类方法。
! 类方法\n\n有时候,一个类需要提供一个不需要任何类实例就能使用的方法。我们已经见过一个这样的方法了,new方法创建了一个Song对象,但是它不属于Song类。 \n\naSong = Song.new(....)\n\n你将会发现类方法贯穿于ruby的库文件之中。比如,File类的对象表示一个打开的文件,但是File也提供了几个类方法,比如删除文件,我们不需要打开文件,直接调用 File.delete ,提供要删除的文件名就行了。 \n\nFile.delete("doomedFile")\n\n__类方法和实例方法定义时候是不一样的,类方法定义的时候要加上类名:__ \n\n<<<\nclass Example\n\n def instMeth # 实例方法\n end\n\n def Example.classMeth # 类方法\n end\n\nend\n<<<\n\n我们的自动点唱机是要收钱的,按歌曲数量而不是时间来收,所以提供长的歌曲不如提供短的歌曲效益高。我们不希望在SongList中出现太长的歌曲,所以我们在SongList里面定一个类方法,判断一首歌是否超过了规定的长度。这个长度存在一个[[常量]]里面(常量以大写字母开头),并且在类体里面初始化这个常量。 \n\n<<<\nclass SongList \n MaxTime = 5*60 # 5 minutes \n \n def SongList.isTooLong(aSong) \n return aSong.duration > MaxTime \n end \nend \nsong1 = Song.new("Bicylops", "Fleck", 260) \nSongList.isTooLong(song1) => false \nsong2 = Song.new("The Calling", "Santana", 468) \nSongList.isTooLong(song2) => true \n<<<\n
继承使你能够创建一个基于一个类的特殊化的类\n//{{{\nclass KaraokeSong < Song\n def initialize(name, artist, duration, lyrics)\n super(name, artist, duration)\n @lyrics = lyrics\n end\nend\n//}}}\n测试输出\n//{{{\naSong = KaraokeSong.new("My Way", "Sinatra", 225, "And now, the...") \naSong.to_s }} "Song: My Way--Sinatra (225)" \n//}}}\n\n这个类已经可以工作了,但是to_s没有显示歌词信息。 \n\n当ruby看到这个 aSong.to_s方法调用,它并不需要知道去哪里找to_s这个方法,而是要在程序运行到此的时候再去调用这个函数。开始在aSong里面找,__如果这个类里面定义了一个和发送给这个对象的消息一样名称的方法的话,就运行这个方法。否则,就会到这个类的父类去找,如果还没找到,再到父类的父类去找。这样一直找到祖先Object。如果找到最高层还没有找到这个方法,一般会返回一个错误。__[实际上,你可以拦截这个错误,你可以在运行时弥补这个错误,见 Object#method_missing ] \n\n//{{{\nclass KaraokeSong \n # ... \n def to_s \n "KS: #{@name}--#{@artist} (#{@duration}) [#{@lyrics}]" \n end \nend \naSong = KaraokeSong.new("My Way", "Sinatra", 225, "And now, the...") \naSong.to_s }} "KS: My Way--Sinatra (225) [And now, the...]" \n//}}}\n\n我们正确地显示了@lyrics 这个实例变量,但是这样做直接在子类里访问了父类的实例变量,为什么这样实现to_s方法不好呢? \n\n这和好的编程风格有关(可以称作decoupling)\n\n我们需要每个类只操作自己内部的状态,当KaraokeSong#to_s 被调用的时候,先在KaraokeSong#to_s调用父类的to_s方法,然后在加上lyric信息返回给调用者。这里需要ruby的关键字"[[super]]"。\n比如改写后如下:\n\n//{{{\nclass KaraokeSong < Song \n # Format ourselves as a string by appending \n # our lyrics to our parent's #to_s value. \n def to_s \n super + " [#{@lyrics}]" \n end \nend \naSong = KaraokeSong.new("My Way", "Sinatra", 225, "And now, the...") \naSong.to_s }} "Song: My Way--Sinatra (225) [And now, the...]" \n//}}}\n\n\n我们显式的声明了KaraokeSong是Song的一个子类,但是并没有说明Song的父类。如果定义一个类时没有指定父类,默认为Object为它的父类。也就是说,所有的类的祖先都是Object类,而且Object的实例方法在子类中也是可以访问的。比如to_s是ruby中大概35个实例方法之一。 \n\n! 继承和 Mixins\n\n像c++这样的面向对象语言都支持多重继承,也就是说一个类可以有多个父类,从每个类继承特性。尽管很有效,但它有时候很危险,有可能产生混乱。 \n\n其他一些语言,比如java、c#,支持单继承,一个类只能有一个父类,尽管清晰明了,容易实现,但是也有一些缺点,因为事实上一个事物同时具备很多种事物的特征。比如一个球,既是球形的东西,也是能弹跳的东西。\n\n<<<\nbtw by TriStones\n这个应该跟哲学对世界的认识论有关。类似[[《老子》]]中所说的道生一,一生二,二生三,三生万物的观念一样。宇宙中的所有事物都生于道。道就是不可名状的万物之源,在这里即抽象为Object。\n<<<\n\nruby采取了有趣而强大的折中办法,你能轻松的实现单继承和多继承。一个ruby只能有一个直接父类,是单继承语言,但是ruby类可以包含其他的mixin(mixin可以看作是一个部分类定义(a partial class definition)中的一些功能,从而引入附加的功能,以这种方式实现了多重继承,并且不会出现多继承语言中的问题。 \n\n上面我们已经看到了类和方法,下面来看看[[对象和属性]],也就是类的实例。
范围无处不在:从一月到十二月,0到9,半熟到完全煮熟,从第50行到第67行等等。如果ruby想要帮助我们很好的根据现实世界来建模,那么它也应该支持这些范围。实际上正是如此,ruby支持的ranges有三种用途:序列,条件,和间隔(sequences, conditions, and intervals)。\n\n! 作为序列\n\nruby的range最常用的用处是表示一个顺序的序列,序列有一个开始点,和一个结束点,和产生序列中下一个值的方法。ruby中,定义序列使用".."和"..."操作符。__".."创建的序列包括两边的边界值,而"..."创建的序列将不包括最大的那个边界值。__ \n<<<\n1..10\n'a'..'z'\n0...anArray.length\n<<<\n\nruby不像其他一些地早期perl那样,把序列保存在一个内部列表中,比如,1..100000在ruby中只是一个Range对象,包括两个指向Fixnum对象的引用。如果需要,你可以把一个Range用to_a转换成一个数组。\n\n<<<\n(1..10).to_a }} [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] \n('bar'..'bat').to_a }} ["bar", "bas", "bat"] \n<<<\n\nRanges实现了一些可以让你对其进行迭代,测试是否包含某个值的方法。 \n<<<\ndigits = 0..9 \ndigits.include?(5) => true \ndigits.min => 0 \ndigits.max => 9 \ndigits.reject {|i| i < 5 } => [5, 6, 7, 8, 9] \ndigits.each do |digit| \n dial(digit) \nend \n<<<\n\n到现在我们的ranges表示的都是数字和字符串型,__作为一个面向对象的语言,ranges也可以用于我们自己创建的对象,但是这个对象必须实现一个succ方法,以返回下一个值,而且这个对象也必须支持<=>来对其进行比较。__调用<=>时,它们比较前后两个对象的大小关系,根据两个对象是小于,等于,还是大于而返回-1, 0, 或者 +1\n\n下面看一个简单的例子,这个类表示由若干个"#"符号组成的一行,我们可以用它来对我们点唱机音量做基于文本的测试。 \n<<<\nclass VU\n\n \n include Comparable\n \n attr :volume\n \n def initialize(volume) # 0..9 \n @volume = volume \n end\n \n def inspect \n '#' * @volume \n end\n \n # Support for ranges\n \n def <=>(other) \n self.volume <=> other.volume \n end\n \n def succ \n raise(IndexError, "Volume too big") if @volume >= 9 \n VU.new(@volume.succ) \n end \nend\n<<<\n \n\n我们可以创建一个VU的range来测试一下:\n\n<<<\nmedium = VU.new(4)..VU.new(7) \nmedium.to_a }} [####, #####, ######, #######] \nmedium.include?(VU.new(3)) }} false \n<<<\n\n! 条件范围( Ranges as Conditions )\n除了表示一系列连续值之外,range还能作为条件表达式。比如,下面代码将接收标准输入,打印出来那些以start开头和以end结尾的代码行。\n\n<<<\nwhile gets\n print if /start/../end/\nend\n<<<\n \n\n! Ranges表示间隔\n\nrang最后一个用处是测试一些值是否在这个间隔之内,这要用到操作符===\n\n<<<\n(1..10) === 5 }} true \n(1..10) === 15 }} false \n(1..10) === 3.14159 }} true \n('a'..'j') === 'c' }} true \n('a'..'j') === 'z' }} false \n<<<
到目前为止我们已经用了一些基本的表达式,毕竟,a=b+c是最基本的了,你即使不看本章,也能写出一大堆的Ruby代码来。但是那样做不是什么有趣的事情;-)。 \nRuby和其它语言的一个不同之处就是任何东西都能返回一个值,几乎所有的东西都是表达式,在实际中,这有什么意义呢?\n\n一些明显得作用是可以实现链式语句:\n\n<<<\na = b = c = 0 » 0 \n[ 3, 1, 7, 0 ].sort.reverse » [7, 3, 1, 0] \n<<<\n\n一些不太起眼的东西,比如C和JAVA中的语句,在Ruby中都是表达式,例如,if和case都返回一个值,这个值就是这些语句中最后执行的那行。\n到目前为止我们已经用了一些基本的表达式,毕竟,a=b+c是最基本的了,你即使不看本章,也能写出一大堆的Ruby代码来。但是那样做不是什么有趣的事情;-)。 \nRuby和其它语言的一个不同之处就是任何东西都能返回一个值,几乎所有的东西都是表达式,在实际中,这有什么意义呢?\n\n一些明显得作用是可以实现链式语句:\n\n<<<\na = b = c = 0 » 0 \n[ 3, 1, 7, 0 ].sort.reverse » [7, 3, 1, 0] \n<<<\n\n一些不太起眼的东西,比如C和JAVA中的语句,在Ruby中都是表达式,例如,if和case都返回一个值,这个值就是这些语句中最后执行的那行。\n<html><pre>\nsongType = if song.mp3Type == MP3::Jazz\n if song.written < Date.new(1935, 1, 1)\n Song::TradJazz\n else\n Song::Jazz\n end\n else\n Song::Other\n end\n\n\n\n rating = case votesCast \n when 0...10 then Rating::SkipThisOne \n when 10...50 then Rating::CouldDoBetter \n else Rating::Rave \n end\n\n \n\nsongType = if song.mp3Type == MP3::Jazz\n if song.written < Date.new(1935, 1, 1)\n Song::TradJazz\n else\n Song::Jazz\n end\n else\n Song::Other\n end\n\n\n\n rating = case votesCast \n when 0...10 then Rating::SkipThisOne \n when 10...50 then Rating::CouldDoBetter \n else Rating::Rave \n end\n</pre></html>\n \n
我们设计一个类的接口的时候,一个重要的问题是,我们应该向外界暴露多少内部实现,外部能访问我们的类有多少限制。如果过多的让外部访问内部的东西,可能增加了耦合,用户越来越依赖我们的类的内部实现,而不是逻辑接口。因为我们要改变一个实例的状态需要调用这个实例的相关方法,控制对实例的方法的访问,就能避免对对象实例的状态的直接修改。Ruby提供了三种保护层次: \n*[[公有方法]](Public methods) \n*[[保护方法]](Protected methods)\n*[[私有方法]](Private methods)\n\n"protected"和"private"两者的区别非常微妙,在ruby中,两者的关系和在其他语言中是不一样的。如果一个方法是protected的,它可以在定义它的实例或者子类的实例来调用。如果一个方法是"private"的,只可以在这个方法所处的对象中被使用,不能直接调用另一个对象的private方法。甚至这个对象就是调用者本身。\nRuby和其他oo语言另一个重要的不同点在于,ruby动态确定访问控制,在程序运行而不是静止时,只有你运行到那一行,才会去判断是否出错。\n\n! 指定访问控制\n在一个类或者模块定义中设定方法的访问控制层次: public, protected,private。有两种定义方法。\n\n如果不带参数使用 public/protected/private,那么这后面的方法默认都是指定的值,比如一行写了private,那么后面的方法默认都是private,除非指定了另外的访问控制符。 \n\n<<<\nclass MyClass\n def method1 # default is 'public'\n #...\n end\n protected # 后面方法将是 'protected'\n def method2 # will be 'protected'\n #...\n end\n private # 后面方法将是 'private'\n def method3 # will be 'private'\n #...\n end\n public # subsequent methods will be 'public'\n\n def method4 # and this will be 'public'\n #...\n end\nend\n<<<\n\n另一种方法,定义方法的时候不指定访问控制符,而是将相关的方法列在对应的访问控制后面,比如:\n \n<<<\nclass MyClass\n\n def method1\n end\n\n # ... and so on\n\n public :method1, :method4\n protected :method2\n private :method3\nend\n<<<\n\n__initialize方法自动声明为private型。__\n\n现在来看看一个例子。假如我们有一个记帐系统,每一个借方(debit)对应一个贷方(credit),我们要求都必须遵守这个规则,所以我们把debit和credit的方法设成private,提供了一个外部接口来处理: \n\n<<<\nclass Accounts\n private\n def debit(account, amount)\n account.balance -= amount\n end\n def credit(account, amount)\n account.balance += amount\n end\n public\n #...\n def transferToSavings(amount)\n debit(@checking, amount)\n credit(@savings, amount)\n end\n #...\nend\n<<<\n\n保护方法(Protected)用来访问同一类中的其他对象实例的内部状态.==For example, we may want to allow the individual Account objects to compare their raw balances, but may want to hide those balances from the rest of the world (perhaps because we present them in a different form).== \n\n<<<\nclass Account\n attr_reader :balance # accessor method 'balance'\n protected :balance # and make it protected\n\n def greaterBalanceThan(other)\n return @balance > other.balance\n end\nend\n<<<\n\n因为属性balance受保护,所以他只对Account对象可用。
我们前面的例子中都涉及到了赋值这一基本表达式,下面,我们来讨论一些关于赋值语句的东西。\n\n一个赋值语句给一个变量或者属性设定一个指定的值,变量或属性在左边,值在右边。然后这个值作为表达式的返回值返回。也就是说,我们可以用链式赋值来给一些变量赋值:\n\n<<<\na = b = 1 + 2 + 3 \na » 6 \nb » 6 \na = (b = 1 + 2) + 3 \na » 6 \nb » 3 \nFile.open(name = gets.chomp) \n<<<\n在Ruby中有两种基本的赋值格式,第一种是指给一个引用某一参数或者常量的对象赋值,这种形式是紧密连接到语言中的。\n<<<\ninstrument = "piano"\nMIDDLE_A = 440\n<<<\n\n另一种是在赋值语句左边使用对象的属性或者元素的引用。\n<<<\naSong.duration = 234\ninstrument["ano"] = "ccolo"\n<<<\n\n这种方法比较特殊,通过调用左值的方法来赋值,也就是说我们可以重写这些方法。\n\n我们已经看过如何定义一个可以修改的属性了,只需要简单的在方法后面以等号结尾即可。这个方法把接收的参数作为赋值语句的右值。\n<<<\nclass Song\n def duration=(newDuration)\n @duration = newDuration\n end\nend\n<<<\n \n\n没有理由要求这些给参数设置值得方法与内部的实例变量一致,或者每个可以修改的属性都要提供一个读方法,反过来也是一样。\n<<<\nclass Amplifier\n def volume=(newVolume)\n self.leftChannel = self.rightChannel = newVolume\n end\n # ...\nend\n<<<\n\nSidebar:在类中使用访问方法( Accessors) \n上面的例子中为什么我们必须要写 self.leftChannel 而不能省掉self呢?一般的,一个类中的方法可以直接调用同类或者父类中的其他方法(默认得接收者是self),但是,对于attribute writers来说这就不管用了,Ruby将把左面的名字作为一个本地变量,而不是一个对写属性方法的调用。 \n \n<<<\nclass BrokenAmplifier \n attr_accessor :leftChannel, :rightChannel \n def volume=(vol) \n leftChannel = self.rightChannel = vol \n end \nend \n \nba = BrokenAmplifier.new \nba.leftChannel = ba.rightChannel = 99 \nba.volume = 5 \nba.leftChannel » 99 \nba.rightChannel » 5 \n<<<\n我们在leftChannel前面忘了写self.了,所以ruby把这个新值赋给了一个方法volume=的一个局部变量,而这个对象的属性没有任何变化。这可能会经常产生问题。\n\n! 并行赋值\n在学习了一段时间程序设计之后,我们可能会遇到要求将两个变量的值互换:\n<<<\nint a = 1;\nint b = 2;\nint temp;\n\ntemp = a; a = b; b = temp; \n<<<\n在Ruby中很简单,只需要:\n<<<\na, b = b, a\n<<<\n\nRuby可以有效的实现并行赋值,在右边的值在被赋给左面的变量或属性之前按照它们的顺讯进行求值,然后对应的赋给左面的属性或变量。一个例子如下,第二行给a,b,c的值分别是x,x+=1,x+=1计算之后的值。\n\n<<<\nx = 0 » 0 \na, b, c = x, (x += 1), (x += 1) » [0, 1, 2] \n<<<\n当一个赋值语句左值多余一时,这个表达式的返回值是一个由右面的值组成的数组,如果一个赋值语句的左值多余右值,多余的左值被设为nil,反过来如果右值多余左值,那么多余的右值将被忽略。在Ruby1.6.2中,如果左值只有一个,右值有多个,那么这些右值将作为一个数组赋给左值。\n\n你也可以在并行赋值语句中分解和扩展数组。如果最后的左值以星号作为前缀,那么所有对应这个得值和以后的值将会组成一个数组,赋给这个左值(如下面第三行的c);类似的,如果最后一个右值是一个数组,你可以加一个星号作为前缀,Ruby将会把这个数组拆开按相应的位置赋给左值(如下面第六行的c,而且,如果这个数组是唯一的右值,这个星号是可以省略的,作为右值得数组自动拆开,如第二行所示)。\n\n<<<\na = [1, 2, 3, 4] \nb, c = a » b == 1, c == 2 \nb, *c = a » b == 1, c == [2, 3, 4] \nb, c = 99, a » b == 99, c == [1, 2, 3, 4] \nb, *c = 99, a » b == 99, c == [[1, 2, 3, 4]] \nb, c = 99, *a » b == 99, c == 1 \nb, *c = 99, *a » b == 99, c == [1, 2, 3, 4] \n<<<\n\n! 嵌套赋值\n并行赋值还有一个值得一提的特性,赋值语句左边还可以包括用括号括起来的变量列表,Ruby中叫做嵌套赋值语句。Ruby首先摘出右值中相应的项进行赋值,然后在进行高层的赋值操作。\n\n<<<\nb, (c, d), e = 1,2,3,4 » b == 1, c == 2, d == nil, e == 3 \nb, (c, d), e = [1,2,3,4] » b == 1, c == 2, d == nil, e == 3 \nb, (c, d), e = 1,[2,3],4 » b == 1, c == 2, d == 3, e == 4 \nb, (c, d), e = 1,[2,3,4],5 » b == 1, c == 2, d == 3, e == 5 \nb, (c,*d), e = 1,[2,3,4],5 » b == 1, c == 2, d == [3, 4], e == 5 \n<<<\n\n! 其它赋值形式\n像其它语言一样,ruby也为a=a+2提供了类似a+=2的快捷方式。\n\n第二种方式是第一种的深入,可以让操作符当成方法来工作。\n\n<<<\nclass Bowdlerize \n def initialize(aString) \n @value = aString.gsub(/[aeiou]/, '*') \n end \n def +(other) \n Bowdlerize.new(self.to_s + other.to_s) \n end \n def to_s \n @value \n end \nend \n \na = Bowdlerize.new("damn ") » d*mn \na += "shame" » d*mn sh*m* \n<<<\n
\nString可能是Ruby最大的内建类了,它有超过75个标准方法。我们不会在这里挨个介绍它们;函数库参考有它们完整的介绍。让我们先来看看几个常用的字符串用法---在日常编程中我们经常会用到的。\n\n让我们回头看看我们的点唱机。尽管它是被设计成联接到互联网上的,但是也保存了一些很流行的歌曲在本地硬盘上。这样,即使我们的网络连接出问题了,我们仍然能够服务我们的顾客。\n\n由于历史的原因(还有其他原因吗?),歌曲列表是成行的保存在一个文件里面的。文件中的每一行内容包含了歌曲,歌曲长度,演唱者和曲名。所有的字段都是用小竖线分隔开的。一个典型的文件如下: \n<<<\n/jazz/j00132.mp3 | 3:45 | Fats Waller | Ain't Misbehavin'\n/jazz/j00319.mp3 | 2:58 | Louis Armstrong | Wonderful World\n/bgrass/bg0732.mp3| 4:09 | Strength in Numbers | Texas Red\n : : : :\n<<<\n\n观察一下数据,很明显在我们建立一些基于这个文件的Song对象之前,我们需要用String类的一些方法来展开和清理这些字段。至少,我们需要:\n\n* 把一行分成一个字段, \n* 把MM:SS格式的时间转换成秒, 然后 \n* 把演唱者名字中额外的空格去掉. \n\n我们的第一个任务是要把每行分成各个字段, [[String#split]] 方法最适合最这个。在这里,我们给 split 传递一个正则表达式,/\ss*|\ss*/,它会用小竖线和空格来分隔一行文本,把文本分成各个字段。还有,因为用文件读取的这行文本后面跟了一个换行符,在我们用split函数之前,我们可以使用String#chomp 来把换行符去掉。 \n<<<\nsongs = SongList.new\nsongFile.each do |line| \n file, length, name, title = line.chomp.split(/\ss*\s|\ss*/) \n songs.append Song.new(title, name, length) \nend \nputs songs[1]\n<<<\n \n产生结果: Song: Wonderful World--Louis Armstrong (2:58)\n\n不幸的是,那个创建原始文件的人在敲演唱者名字的时候是按列敲的,有些名字里面可能包含额外的空格。这样那些名字在我们极好的,高科技的,24小时运行的显示板上显示会很难看。我们必须去掉那些额外的空格才能继续我们的工作。有很多方法来做这个工作,但是最简单的可能是用[[String#squeeze]] ,它会修饰重复的字符。我们在这里使用这个方法的 squeeze! 格式,它会改变适当位置的字符串。\n<<<\nsongs = SongList.new\n\nsongFile.each do |line| \n file, length, name, title = line.chomp.split(/\ss*\s|\ss*/) \n name.squeeze!(" ") \n songs.append Song.new(title, name, length) \nend \nputs songs[1]\n<<<\n \n产生结果: Song: Wonderful World--Louis Armstrong (2:58)\n\n最后,还有一个小问题---时间的格式问题:文件说 2:58,我们想要用秒数来表示,178秒。我们可以再次使用 split 函数,把用冒号分隔的两个字段分开。\n<<<\nmins, secs = length.split(/:/)\n<<<\n\n不过,我们这里使用另一个相关的函数。[[String#scan]] 和 split有点相象,都可以通过一个模式匹配把一个字符串变成几部分。 但是和split不同的是,scan允许你指定用来匹配字段的模式串。在咱们这个例子中,我们想为分字段和秒字段匹配一个或多个数字。一个或多个数字的正则式是 /\sd+/。\n<<<\nsongs = SongList.new\nsongFile.each do |line|\n file, length, name, title = line.chomp.split(/\ss*\s|\ss*/)\n name.squeeze!(" ")\n mins, secs = length.scan(/\sd+/)\n songs.append Song.new(title, name, mins.to_i*60+secs.to_i)\nend\nputs songs[1]\n<<<\n \n产生结果: Song: Wonderful World--Louis Armstrong (178)\n\n我们的点唱机有关键字搜索的能力。给一个歌曲名或者演唱者姓名中的单词,它能够列出所有匹配的歌曲。比如,敲进"fats",它可能列出 Fats Domino, Fats Navarro, 和Fats Waller的歌曲。我们通过建立一个索引类来实现这个功能。给它一个对象和一些字符串,它会索引出那个对象里所有包含在字符串里的单词(有两个或者多个字符的)。这会用到String类里面另一些其他方法。\n<<<\nclass WordIndex\n def initialize\n @index = Hash.new(nil)\n end\n def index(anObject, *phrases)\n phrases.each do |aPhrase|\n aPhrase.scan /\sw[-\sw']+/ do |aWord| # extract each word\n aWord.downcase!\n @index[aWord] = [] if @index[aWord].nil?\n @index[aWord].push(anObject)\n end\n end\n end\n def lookup(aWord)\n @index[aWord.downcase]\n end\nend\n<<<\n\nString#scan 方法能从一个字符串里面提取出符合一个正则表达式 的元素。在这个例子里面模式串“\sw[-\sw']+”匹配任何能出现在单词里的字符,后面跟一个或多个在方括号里指定的东东(一个小横线,另一个单词符号或者一个单引号)。我们会在56页开始部分更详细地介绍正则表达式。要让我们的搜索大小写不敏感,我们把刚才我们提取出来的字段和传进来的关键字转化成小写。注意在第一个 downcase! 方法后面的感叹号。就像以前我们使用的 squeeze! 方法一样,__"!"是一个标识来表明方法会在某个地方改变接受者__,在这里表示把字符串变成小写。[这段代码里面有一个Bug, 歌曲"Gone, Gone, Gone"会被索引三次。你能想一个方法修正它吗?]\n\n我们来扩展一下我们的 SongList 类,让它能够在歌曲加进来的时候索引它们,然后加一个用一个字符串查找歌曲的方法。\n<<<\nclass SongList\n def initialize\n @songs = Array.new\n @index = WordIndex.new\n end\n def append(aSong)\n @songs.push(aSong)\n @index.index(aSong, aSong.name, aSong.artist)\n self\n end\n def lookup(aWord)\n @index.lookup(aWord)\n end\nend\n<<<\n\n最后,我们来测试一下: \n<<<\nsongs = SongList.new\nsongFile.each do |line|\n file, length, name, title = line.chomp.split(/\ss*\s|\ss*/)\n name.squeeze!(" ")\n mins, secs = length.scan(/\sd+/)\n songs.append Song.new(title, name, mins.to_i*60+secs.to_i)\nend\nputs songs.lookup("Fats")\nputs songs.lookup("ain't")\nputs songs.lookup("RED")\nputs songs.lookup("WoRlD")\n<<<\n \n产生结果: Song: Ain't Misbehavin'--Fats Waller (225)\nSong: Ain't Misbehavin'--Fats Waller (225)\nSong: Texas Red--Strength in Numbers (249)\nSong: Wonderful World--Louis Armstrong (178)\n
上面我们知道了,Ruby支持简单的循环,比如,Ruby没有for循环,而c和JAV等都支持for循环的,但是Ruby提供了其他的机制,比如迭代,提供了类似的功能。\n\n让我们看看一个例子:\n\n<<<\n3.times do\n print "Ho! "\nend\n<<<\n \nproduces: Ho! Ho! Ho!\n\n \n\n这可以避免off-by-1 错误,这个循环将执行3次。除了times,整数还可以接收一些方法来执行循环,比如downto,upto,和step等。比如,传统的从0到9的循环(类似for( i=0; i < 10; i++)) 类似下面的样子:\n\n<<<\n0.upto(9) do |x|\n print x, " "\nend\n<<<\n \nproduces: 0 1 2 3 4 5 6 7 8 9\n\n \n\n一个从0到12,步长为3的循环如下:\n<<<\n0.step(12, 3) {|x| print x, " " }\n<<<\n \nproduces: 0 3 6 9 12\n\n \n\n用于数组和其它容器的迭代的each方法也可以用来循环。\n<<<\n[ 1, 1, 2, 3, 5 ].each {|val| print val, " " }\n<<<\n \nproduces: 1 1 2 3 5\n\n \n\n如果一个类支持了each方法,那么在模块Enumerable 中的方法也可以直接使用。比如,File类提供了each方法,依次返回一个文件的每一行。使用Enumerable中的grep方法,我们可以只迭代符合条件的行。\n<<<\nFile.open("ordinal").grep /d$/ do |line|\n print line\nend\n<<<\n \nproduces: second\nthird\n\n \n\n最后也是最简单的,Ruby提供了一个内建的最基本的迭代器loop。\n\n<<<\nloop {\n # block ...\n}\n<<<\n \nloop迭代器一直调用给定的block(或者你调用了break跳出循环,后面会讲到)。\n\n! For ... In\n前面我们说道Ruby支持的最基本循环视while和until,而for指的什么呢,可以看如下代码:\n\n<<<\nfor aSong in songList\n aSong.play\nend\n<<<\n \n\nRuby将会把它翻译为如下:\n\n<<<\nsongList.each do |aSong|\n aSong.play\nend\n<<<\n \n\n__for和each的唯一区别是局部变量的作用域。__\n\n你可以在支持each的类上使用for方法,比如Array或者Range。 \n<<<\nfor i in ['fee', 'fi', 'fo', 'fum']\n print i, " "\nend\nfor i in 1..3\n print i, " "\nend\nfor i in File.open("ordinal").find_all { |l| l =~ /d$/}\n print i.chomp, " "\nend\n<<<\n \nproduces: fee fi fo fum 1 2 3 second third\n\n \n\n一旦你的类支持了each方法,你就可以使用for来进行遍历。\n<<<\nclass Periods\n def each\n yield "Classical"\n yield "Jazz"\n yield "Rock"\n end\nend\n \nperiods = Periods.new \nfor genre in periods \n print genre, " " \nend\n<<<\n \nproduces: Classical Jazz Rock\n\n! Break, Redo, 和 Next\n循环控制结构 break, redo, 和 next 让你可以控制循环或者迭代器的流程。\n\nbreak 立即结束当前循环,然后跳出去执行循环后面的语句。redo从这次循环体的头开始重新执行,但是不会在对条件进行运算或者从迭代中取下一个值。next跳到本次循环末尾,开始执行下一次循环。 \n<<<\nwhile gets\n next if /^\ss*#/ # skip comments\n break if /^END/ # stop at end\n # substitute stuff in backticks and try again\n redo if gsub!(/`(.*?)`/) { eval($1) }\n # process line ...\nend\n<<<\n \n这些关键字也可以用在基于迭代器的循环机制中。\n\n<<<\ni=0\nloop do\n i += 1\n next if i < 3\n print i\n break if i > 4\nend\n<<<\n \nproduces: 345\n\n \n\n! Retry\nredo使一个循环从当前迭代中重新执行。有时候,你需要从新开始一个循环,retry从新开始任何地迭代循环。\n\n<<<\nfor i in 1..100\n print "Now at #{i}. Restart? "\n retry if gets =~ /^y/i\nend\n<<<\n\n运行上面的程序,结果如下: \n<<<\nNow at 1. Restart? n\nNow at 2. Restart? y\nNow at 1. Restart? n\n . . .\n<<<\n \nretry 将重新计算条件值,然后再开始循环。Ruby文档有如下例子: \n<<<\ndef doUntil(cond)\n yield\n retry unless cond\nend\n\n \ni = 0 \ndoUntil(i > 3) { \n print i, " " !\n i += 1 \n}\n<<<\n \nproduces: 0 1 2 3 4\n\n \n