Documentation.st 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. Smalltalk current createPackage: 'Documentation' properties: #{}!
  2. Object subclass: #ChapterSelectionAnnouncement
  3. instanceVariableNames: 'id'
  4. package: 'Documentation'!
  5. !ChapterSelectionAnnouncement methodsFor: 'accessing'!
  6. id
  7. ^id
  8. !
  9. id: aString
  10. id := aString
  11. ! !
  12. Object subclass: #ClassSelectionAnnouncement
  13. instanceVariableNames: 'theClass'
  14. package: 'Documentation'!
  15. !ClassSelectionAnnouncement methodsFor: 'accessing'!
  16. theClass
  17. ^theClass
  18. !
  19. theClass: aClass
  20. theClass := aClass
  21. ! !
  22. !ClassSelectionAnnouncement class methodsFor: 'instance creation'!
  23. on: aClass
  24. ^self new
  25. theClass: aClass;
  26. yourself
  27. ! !
  28. Widget subclass: #DocChapter
  29. instanceVariableNames: 'title contents parent level'
  30. package: 'Documentation'!
  31. !DocChapter methodsFor: 'accessing'!
  32. announcer
  33. ^DocumentationBuilder current announcer
  34. !
  35. chapters
  36. "A doc chapter can contain sub chapters"
  37. ^#()
  38. !
  39. contents
  40. ^contents ifNil: ['']
  41. !
  42. contents: aString
  43. contents := aString
  44. !
  45. cssClass
  46. ^'doc_chapter'
  47. !
  48. htmlContents
  49. ^(Showdown at: #converter) new makeHtml: self contents
  50. !
  51. id
  52. "The id is used in url fragments.
  53. It must be unique amoung all chapters"
  54. ^self title replace: ' ' with: '-'
  55. !
  56. level
  57. ^self parent ifNil: [1] ifNotNil: [self parent level +1]
  58. !
  59. level: anInteger
  60. level := anInteger
  61. !
  62. parent
  63. ^parent
  64. !
  65. parent: aChapter
  66. parent := aChapter
  67. !
  68. title
  69. ^title ifNil: ['']
  70. !
  71. title: aString
  72. title := aString
  73. ! !
  74. !DocChapter methodsFor: 'actions'!
  75. displayChapter: aChapter
  76. DocumentationBuilder current widget displayChapter: aChapter
  77. !
  78. selectChapter: aChapter
  79. document location hash: aChapter id
  80. !
  81. selectClass: aClass
  82. DocumentationBuilder current announcer announce: (ClassSelectionAnnouncement on: aClass)
  83. ! !
  84. !DocChapter methodsFor: 'initialization'!
  85. initialize
  86. super initialize.
  87. self subscribe
  88. ! !
  89. !DocChapter methodsFor: 'rendering'!
  90. renderDocOn: html
  91. | div |
  92. html h1 with: self title.
  93. self renderNavigationOn: html.
  94. div := html div class: 'contents'.
  95. div asJQuery html: self htmlContents
  96. !
  97. renderLinksOn: html
  98. html ul
  99. class: 'links';
  100. with: [
  101. self chapters do: [:each |
  102. html li with: [
  103. html a
  104. with: each title;
  105. onClick: [self selectChapter: each]]]]
  106. !
  107. renderNavigationOn: html
  108. self parent ifNotNil: [
  109. html div
  110. class: 'navigation'; with: [
  111. html a
  112. with: '← back to ', self parent title;
  113. onClick: [self selectChapter: self parent]]]
  114. !
  115. renderOn: html
  116. html div
  117. class: self cssClass;
  118. with: [
  119. self renderDocOn: html.
  120. self renderLinksOn: html]
  121. ! !
  122. !DocChapter methodsFor: 'subscriptions'!
  123. subscribe
  124. self announcer on: ChapterSelectionAnnouncement do: [:ann |
  125. ann id = self id ifTrue: [self displayChapter: self]]
  126. ! !
  127. DocChapter subclass: #ClassDocChapter
  128. instanceVariableNames: 'theClass'
  129. package: 'Documentation'!
  130. !ClassDocChapter methodsFor: 'accessing'!
  131. contents
  132. ^self theClass comment isEmpty
  133. ifTrue: [self theClass name, ' is not documented yet.']
  134. ifFalse: [self theClass comment]
  135. !
  136. cssClass
  137. ^'doc_class ', super cssClass
  138. !
  139. initializeWithClass: aClass
  140. theClass := aClass
  141. !
  142. theClass
  143. ^theClass
  144. !
  145. title
  146. ^self theClass name
  147. ! !
  148. !ClassDocChapter methodsFor: 'rendering'!
  149. renderLinksOn: html
  150. html ul
  151. class: 'links';
  152. with: [
  153. html li with: [html a
  154. with: 'Browse this class';
  155. onClick: [Browser openOn: self theClass]]]
  156. ! !
  157. !ClassDocChapter methodsFor: 'subscriptions'!
  158. subscribe
  159. super subscribe.
  160. self announcer
  161. on: ClassSelectionAnnouncement do: [:ann |
  162. ann theClass = self theClass ifTrue: [
  163. self selectChapter: self]]
  164. ! !
  165. !ClassDocChapter class methodsFor: 'accessing'!
  166. on: aClass
  167. ^self basicNew
  168. initializeWithClass: aClass;
  169. initialize;
  170. yourself
  171. ! !
  172. DocChapter subclass: #ClassesIndexChapter
  173. instanceVariableNames: ''
  174. package: 'Documentation'!
  175. !ClassesIndexChapter methodsFor: 'accessing'!
  176. alphabet
  177. ^'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  178. !
  179. cssClass
  180. ^'index_doc ', super cssClass
  181. !
  182. title
  183. ^'Smalltalk classes by index'
  184. ! !
  185. !ClassesIndexChapter methodsFor: 'rendering'!
  186. renderDocOn: html
  187. html h1 with: self title.
  188. self alphabet do: [:letter || classes |
  189. classes := Smalltalk current classes select: [:each | each name first = letter].
  190. classes ifNotEmpty: [html h2 with: letter].
  191. html ul with: [
  192. (classes sorted: [:a :b | a name < b name])
  193. do: [:each |
  194. html li with: [html a
  195. with: each name;
  196. onClick: [self selectClass: each]]]]]
  197. ! !
  198. DocChapter subclass: #PackageDocChapter
  199. instanceVariableNames: 'package chapters'
  200. package: 'Documentation'!
  201. !PackageDocChapter methodsFor: 'accessing'!
  202. chapters
  203. ^chapters
  204. !
  205. contents
  206. ^'Classes in package ', self package name, ':'
  207. !
  208. package
  209. ^package
  210. !
  211. title
  212. ^'Package ', self package name
  213. ! !
  214. !PackageDocChapter methodsFor: 'initialization'!
  215. initializeWithPackage: aPackage
  216. package := aPackage.
  217. chapters := (aPackage classes sorted: [:a :b | a name < b name]) collect: [:each |
  218. (ClassDocChapter on: each)
  219. parent: self;
  220. yourself]
  221. ! !
  222. !PackageDocChapter class methodsFor: 'instance creation'!
  223. on: aPackage
  224. ^self basicNew
  225. initializeWithPackage: aPackage;
  226. initialize;
  227. yourself
  228. ! !
  229. DocChapter subclass: #TutorialsChapter
  230. instanceVariableNames: ''
  231. package: 'Documentation'!
  232. !TutorialsChapter methodsFor: 'accessing'!
  233. contents
  234. ^'You can find a list of [Tutorials](https://github.com/amber-smalltalk/amber/wiki/Tutorials) on the [Github wiki](https://github.com/amber-smalltalk/amber/wiki). If you are new to Smalltalk, you can also learn Amber online with [ProfStef](http://www.amber-lang.net/learn.html).'
  235. !
  236. title
  237. ^'Tutorials'
  238. ! !
  239. Object subclass: #DocumentationBuilder
  240. instanceVariableNames: 'chapters announcer widget'
  241. package: 'Documentation'!
  242. !DocumentationBuilder methodsFor: 'accessing'!
  243. announcer
  244. ^announcer ifNil: [announcer := Announcer new]
  245. !
  246. chapters
  247. ^chapters ifNil: [chapters := self buildChapters]
  248. !
  249. widget
  250. ^widget ifNil: [widget := DocumentationWidget on: self]
  251. ! !
  252. !DocumentationBuilder methodsFor: 'building'!
  253. build
  254. self buildOnJQuery: ('body' asJQuery)
  255. !
  256. buildChapters
  257. ^((self class methodDictionary values sorted: [:a :b | a selector < b selector])
  258. select: [:each | each category = 'chapters'])
  259. collect: [:each | self perform: each selector]
  260. !
  261. buildOn: aCanvas
  262. aCanvas with: self widget.
  263. self
  264. checkHashChange;
  265. checkHash
  266. !
  267. buildOnJQuery: aJQuery
  268. self buildOn: (HTMLCanvas onJQuery: aJQuery)
  269. ! !
  270. !DocumentationBuilder methodsFor: 'chapters'!
  271. ch1introduction
  272. ^DocChapter new
  273. title: 'Introduction';
  274. contents: '
  275. ##Amber Smalltalk in a nutshell
  276. Amber is an implementation of the Smalltalk-80 language. It is designed to make client-side web development **faster, easier and more fun** as it allows developers to write HTML5 applications in a live Smalltalk environment!!
  277. Amber is written in itself, including the IDE and the compiler and it runs **directly inside your browser**. The IDE is fairly complete with a class browser, workspace, transcript, unit test runner, object inspectors, cross reference tools and even a debugger.
  278. Noteworthy features:
  279. - Amber is semantically and syntactically very close to [Pharo Smalltalk](http://www.pharo-project.org). Pharo is considered the reference implementation.
  280. - Amber **seamlessly interacts with JavaScript** and can use its full eco system of libraries without any glue code needed.
  281. - Amber **has no dependencies** and can be used in any JavaScript runtime, not only inside browsers. An important example is [Node.js](http://nodejs.org).
  282. - Amber is a live Smalltalk that **compiles incrementally into efficient JavaScript** often mapping one-to-one with JavaScript equivalents.
  283. - Amber has a **Seaside influenced canvas library** to dynamically generate HTML.
  284. ## Why Amber?
  285. - JavaScript is quite a broken language with lots of traps and odd quirks. It is the assembler of the Internet which is cool, but we don''t want to write in it.
  286. - Amber is a language and environment built for the web. With Amber, client-side web development finally gets the power and productivity that exists in other Smalltalk dialects.
  287. - Smalltalk has a simple class model with a lightweight syntax for closures, it is in many ways a perfect match for the Good Parts of JavaScript.
  288. Smalltalk stands head and shoulders above most other languages for clarity, conciseness, and human-friendliness.
  289. As a language, it is immensely clean and mature, both syntactically and semantically. It is a pure OO language, with objects all the way down.
  290. - Having a true live & incremental development environment where you can build your application interactively in the browser is unbeatable.
  291. ## Disclaimer
  292. This documentation doesn''t aim to teach Smalltalk.
  293. Knowledge of Smalltalk is needed to understand the topics covered in this documentation.
  294. If you want to learn the Smalltalk language, you can read the excellent [Pharo By Example](http://www.pharobyexample.org) book.
  295. '
  296. !
  297. ch2differencesWithOtherSmalltalks
  298. ^DocChapter new
  299. title: 'Differences with other Smalltalks';
  300. contents: '
  301. Amber has some differences with other Smalltalk implementations. This makes porting code a non-trivial thing, but still quite manageable.
  302. Because it maps Smalltalk constructs one-to-one with the JavaScript equivalent, including Smalltalk classes to JavaScript constructors, the core class library is simplified compared to Pharo Smalltalk.
  303. And since we want Amber to be useful in building lean browser apps we can''t let it bloat too much.
  304. But apart from missing things other Smalltalks may have, there are also things that are plain different:
  305. - The collection class hierarchy is much simpler compared to most Smalltalk implementations. In part this is because we want to map reasonably well with JavaScript counter parts.
  306. - As of today, there is no SortedCollection. The size of arrays is dynamic, and they behave like an ordered collection. They can also be sorted with the `#sort*` methods.
  307. - The `Date` class behaves like the `Date` and `TimeStamp` classes in Pharo Smalltalk. Therefore both `Date today` and `Date now` are valid in Amber.
  308. - Amber does not have class Character, but `String` does implement some of Character behavior so a single character String can work as a Character.
  309. - Amber does support **class instance variables**, but not class variables.
  310. - Amber only has global classes and packages, but not arbitrary objects. Use classes instead like `Smalltalk current` instead of `Smalltalk` etc.
  311. - Amber does not support pool dictionaries.
  312. - Amber uses **< ...javascript code... >** to inline JavaScript code and does not have pragmas.
  313. - Amber does not have class categories. The left side in the browser lists real Packages, but they feel much the same.
  314. '
  315. !
  316. ch3GettingStarted
  317. ^DocChapter new
  318. title: 'Getting started';
  319. contents: '
  320. To get started hacking in Amber you can basically take three routes, independent of your platform:
  321. 1. Just **try it out directly** at [www.amber-lang.net](http://www.amber-lang.net) - click the **Class browser** button there. But you will **not be able to save any code you write**!!
  322. Still, it works fine for looking at the IDE and playing around. Just **don''t press F5/reload** - it will lose any code you have written.
  323. 2. Download an Amber zip-ball, install [Nodejs](http://www.nodejs.org), fire up the Amber server and then open Amber from localhost - then you **can save code**. Detailed instructions are below!!
  324. 3. Same as above but install git first and get a proper clone from [http://github.com/NicolasPetton/amber](http://github.com/NicolasPetton/amber) instead of a zip/tar-ball.
  325. If you want to **contribute to Amber itself** this is really what you want to do. In fact, in most cases this is what you want to do. It requires installing git first, but it is quite simple - although we leave this bit as an "exercise to the reader" :)
  326. ## Downloading Amber
  327. Currently you can download in zip or tar-ball format, either cutting edge or a release. [Downloads are available here](https://github.com/NicolasPetton/amber/archives/amber).
  328. Unpack wherever you like, but I would rename the directory that is unpacked to something slightly shorter - like say "amber". :)
  329. And yes, at this point you can double click the index.html file in the amber directory to get the IDE up, but again, **you will not be able to save code**. So please continue below :)
  330. ## Installing Node.js
  331. [Node](http://www.nodejs.org) (for short) is simply the V8 Javascript VM from Google (used in Chrome) hooked together with some hard core C-libraries for doing "evented I/O".
  332. Basically it''s JavaScript for the server - on asynch steroids. Amber runs fine in Node and we use it for several Amber tools, like amberc (the command line Amber compiler) or the Amber server (see below).
  333. There are also several Amber-Node examples to look at if you want to play with running Amber programs server side. **In short - you really want to install Nodejs. :)**
  334. - Installing Node on Linux can be done using your package tool of choice (`apt-get install nodejs` for example) or any other way described at [the download page](http://nodejs.org/#download).
  335. - Installing Node on MacOS or Windows is probably done best by using the [installers available at Nodejs.org](http://nodejs.org/#download).
  336. ## Starting Amber server
  337. Nicolas has written a minimal webDAV server that is the easiest way to get up and running Amber with the ability to save code. This little server is written in... Amber!!
  338. And it runs on top of Node. So to start it up serving your brand new directory tree of sweet Amber you do:
  339. cd amber (or whatever you called the directory you unpackaged)
  340. ./bin/server (in windows you type `node server\server.js` instead)
  341. It should say it is listening on port 4000. If it does, hooray!! That means both Node and Amber are good. In Windows you might get a question about opening that port in the local firewall - yep, do it!!
  342. ## Firing up Amber
  343. The Amber IDE is written in... Amber. It uses [jQuery](http://jquery.com) and runs right in your browser as a ... well, a web page.
  344. We could open it up just using a file url - but the reason we performed the previous steps is so that we can load the IDE web page from a server that can handle PUTs (webDAV) of source code.
  345. According to web security Amber can only do PUT back to the same server it was loaded from. Thus we instead want to open it [through our little server now listening on port 4000](http://localhost:4000/index.html).
  346. Clicking that link and then pressing the **Class browser** should get your Amber IDE running with the ability to commit modified packages locally.
  347. To verify that you can indeed commit now - just select a Package in the browser, like say "Examples" and press the **Commit** button below. **If all goes well nothing happens :)**.
  348. So in order to really know if it worked we can check the modified date on the files **amber/st/Examples.st**, **amber/js/Examples.js** and **amber/js/Examples.deploy.js** - they should be brand new.
  349. NOTE: We can use any webDAV server and Apache2 has been used earlier and works fine. But the Amber server is smaller and simpler to start.
  350. '
  351. !
  352. ch4Tutorials
  353. ^TutorialsChapter new
  354. !
  355. ch5Index
  356. ^ClassesIndexChapter new
  357. !
  358. ch6KernelObjects
  359. ^PackageDocChapter on: (Package named: 'Kernel-Objects')
  360. !
  361. ch7KernelClasses
  362. ^PackageDocChapter on: (Package named: 'Kernel-Classes')
  363. !
  364. ch8KernelCollection
  365. ^PackageDocChapter on: (Package named: 'Kernel-Collections')
  366. !
  367. ch9KernelMethods
  368. ^PackageDocChapter on: (Package named: 'Kernel-Methods')
  369. ! !
  370. !DocumentationBuilder methodsFor: 'routing'!
  371. checkHash
  372. | hash presentation |
  373. hash := document location hash replace: '^#' with: ''.
  374. self announcer announce: (ChapterSelectionAnnouncement new
  375. id: hash;
  376. yourself)
  377. !
  378. checkHashChange
  379. (window jQuery: window) bind: 'hashchange' do: [self checkHash]
  380. ! !
  381. !DocumentationBuilder methodsFor: 'updating'!
  382. update
  383. chapters := nil.
  384. announcer := nil.
  385. widget := nil.
  386. (window jQuery: '.documentation') remove.
  387. self build
  388. ! !
  389. DocumentationBuilder class instanceVariableNames: 'current'!
  390. !DocumentationBuilder class methodsFor: 'accessing'!
  391. current
  392. ^current ifNil: [current := self new]
  393. ! !
  394. !DocumentationBuilder class methodsFor: 'initialization'!
  395. initialize
  396. self current build
  397. ! !
  398. Widget subclass: #DocumentationWidget
  399. instanceVariableNames: 'builder selectedChapter chapterDiv'
  400. package: 'Documentation'!
  401. !DocumentationWidget methodsFor: 'accessing'!
  402. builder
  403. ^builder
  404. !
  405. builder: aDocumentationBuilder
  406. builder := aDocumentationBuilder
  407. !
  408. chapters
  409. ^self builder chapters
  410. !
  411. selectedChapter
  412. ^selectedChapter ifNil: [selectedChapter := self chapters first]
  413. !
  414. selectedChapter: aChapter
  415. ^selectedChapter := aChapter
  416. ! !
  417. !DocumentationWidget methodsFor: 'actions'!
  418. displayChapter: aChapter
  419. self selectedChapter: aChapter.
  420. self updateChapterDiv
  421. !
  422. selectChapter: aChapter
  423. document location hash: aChapter id
  424. ! !
  425. !DocumentationWidget methodsFor: 'rendering'!
  426. renderChapterMenu: aChapter on: html
  427. html a
  428. with: aChapter title;
  429. onClick: [
  430. self selectChapter: aChapter].
  431. html ol with: [
  432. aChapter chapters do: [:each |
  433. html li with: [
  434. self renderChapterMenu: each on: html]]]
  435. !
  436. renderMenuOn: html
  437. html div
  438. class: 'menu';
  439. with: [
  440. html ol with: [
  441. self chapters do: [:each |
  442. html li with: [
  443. self renderChapterMenu: each on: html]]]]
  444. !
  445. renderOn: html
  446. html div
  447. class: 'documentation';
  448. with: [
  449. self renderMenuOn: html.
  450. chapterDiv := html div.
  451. self updateChapterDiv]
  452. ! !
  453. !DocumentationWidget methodsFor: 'updating'!
  454. updateChapterDiv
  455. chapterDiv contents: [:html |
  456. html with: self selectedChapter]
  457. ! !
  458. !DocumentationWidget class methodsFor: 'instance creation'!
  459. on: aBuilder
  460. ^self new
  461. builder: aBuilder;
  462. yourself
  463. ! !