|
1 |
| -# <img align="left" src="durian-rx.png"> DurianRx: Reactive getters, powered by RxJava and ListenableFuture |
2 |
| - |
3 |
| -[](https://bintray.com/diffplug/opensource/durian-rx/view) |
4 |
| -[](https://github.com/diffplug/durian-rx/releases/latest) |
5 |
| -[](https://diffplug.github.io/durian-rx/javadoc/1.0.1/) |
| 1 | +# <img align="left" src="freshmark.png"> FreshMark: Keep your markdown fresh |
| 2 | +<!---freshmark shields |
| 3 | +output = [ |
| 4 | + link(shield('Maven artifact', 'mavenCentral', '{{group}}:{{name}}', 'blue'), 'https://bintray.com/{{org}}/opensource/{{name}}/view'), |
| 5 | + link(shield('Latest version', 'latest', '{{stable}}', 'blue'), 'https://github.com/{{org}}/{{name}}/releases/latest'), |
| 6 | + link(shield('Javadoc', 'javadoc', 'OK', 'blue'), 'https://{{org}}.github.io/{{name}}/javadoc/{{stable}}/'), |
| 7 | + link(shield('License Apache', 'license', 'Apache', 'blue'), 'https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)'), |
| 8 | + '', |
| 9 | + link(shield('Changelog', 'changelog', '{{version}}', 'bright-green'), 'CHANGES.md'), |
| 10 | + link(image('Travis CI', 'https://travis-ci.org/{{org}}/{{name}}.svg?branch=master'), 'https://travis-ci.org/{{org}}/{{name}}') |
| 11 | + '', |
| 12 | + link(shield('Gradle', 'supported', 'https://github.com/diffplug/spotless#adding-spotless-to-java-source', 'green'), 'CHANGES.md'), |
| 13 | + link(shield('CLI', 'supported', '{{version}}', 'green'), 'CHANGES.md'), |
| 14 | + ].join('\n') |
| 15 | +--> |
| 16 | +[](https://bintray.com/diffplug/opensource/durian/view) |
| 17 | +[](https://github.com/diffplug/durian/releases/latest) |
| 18 | +[](https://diffplug.github.io/durian/javadoc/3.2.0/) |
6 | 19 | [](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0))
|
7 | 20 |
|
8 |
| -[](CHANGES.md) |
9 |
| -[](https://travis-ci.org/diffplug/durian-rx) |
| 21 | +[](CHANGES.md) |
| 22 | +[](https://travis-ci.org/diffplug/durian) |
| 23 | +<!---freshmark /shields --> |
| 24 | + |
| 25 | +Generating URL's for the buttons above is tricky. Once they're generated, it's hard to keep them up-to-date as new versions are released. FreshMark solves the "Markdown with variables" problem by embedding tiny JavaScript programs into the comments of your Markdown, which statically generate the rest of the document. By running these programs as part of your build script, your project's documentation will always stay up-to-date. |
| 26 | + |
| 27 | +Here is what the code looks like for the shields at the top of this document: |
| 28 | + |
| 29 | +```javascript |
| 30 | +<!---freshmark shields |
| 31 | +output = [ |
| 32 | + link(shield('Maven artifact', 'mavenCentral', '{{group}}:{{name}}', 'blue'), 'https://bintray.com/{{org}}/opensource/{{name}}/view'), |
| 33 | + link(shield('Latest version', 'latest', '{{stable}}', 'blue'), 'https://github.com/{{org}}/{{name}}/releases/latest'), |
| 34 | + link(shield('Javadoc', 'javadoc', 'OK', 'blue'), 'https://{{org}}.github.io/{{name}}/javadoc/{{stable}}/'), |
| 35 | + link(shield('License Apache', 'license', 'Apache', 'blue'), 'https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)'), |
| 36 | + ].join('\n') |
| 37 | +--> |
| 38 | +... (the results from the last time that FreshMark was run) |
| 39 | +<!---freshmark /shields --> |
| 40 | +``` |
10 | 41 |
|
11 |
| -DurianRx unifies RxJava's [Observable](http://reactivex.io/documentation/observable.html) with Guava's [ListenableFuture](https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained). If you happen to be using SWT as a widget toolkit, then you'll want to look at [DurianSwt](https://github.com/diffplug/durian-swt) as well. |
| 42 | +In addition to generating Markdown from scratch, FreshMark can also modify existing Markdown. This ensures that any inline documentation links stay fresh. |
12 | 43 |
|
13 |
| -```java |
14 |
| -Observable<SomeType> observable = someObservable(); |
15 |
| -ListenableFuture<SomeType> future = someFuture(); |
16 |
| -Rx.subscribe(observable, val -> doSomething(val)); |
17 |
| -Rx.subscribe(future, val -> doSomething(val)); |
| 44 | +```javascript |
| 45 | +<!---freshmark javadoc |
| 46 | +output = prefixDelimReplace(input, 'https://{{org}}.github.io/{{name}}/javadoc/', '/', stable) |
| 47 | +--> |
| 48 | +To run FreshMark on some text, call [FreshMark.compile()](https://diffplug.github.io/freshmark/javadoc/1.0/com/diffplug/freshmark/FreshMark.html) |
| 49 | +<!---freshmark /javadoc --> |
18 | 50 | ```
|
19 | 51 |
|
20 |
| -It also provides [reactive getters](src/com/diffplug/common/rx/RxGetter.java?ts=4), a simple abstraction for piping data which allows access via `T get()` or `Observable<T> asObservable()`. |
| 52 | +## How it works |
21 | 53 |
|
22 |
| -```java |
23 |
| -RxBox<Point> mousePos = RxBox.of(new Point(0, 0)); |
24 |
| -this.addMouseListener(e -> mousePos.set(new Point(e.x, e.y))); |
| 54 | +FreshMark has three pieces, `SECTION`, `PROGRAM`, and `INPUT`. They are parsed as shown below: |
25 | 55 |
|
26 |
| -Rectangle hotSpot = new Rectangle(0, 0, 10, 10) |
27 |
| -RxGetter<Boolean> isMouseOver = mousePos.map(hotSpot::contains); |
| 56 | +```javascript |
| 57 | +<!---freshmark SECTION (identifier) |
| 58 | +PROGRAM (javascript) |
| 59 | +--> |
| 60 | +INPUT (markdown) |
| 61 | +<!---freshmark /SECTION --> |
28 | 62 | ```
|
29 | 63 |
|
30 |
| -Debugging an error which involves lots of callbacks can be difficult. To make this easier, DurianRx includes a [tracing capability](src/com/diffplug/common/rx/RxTracingPolicy.java?ts=4), which makes this task easier. |
| 64 | +When `PROGRAM` is run, there are two magic variables: |
31 | 65 |
|
32 |
| -```java |
33 |
| -// anytime an error is thrown in an Rx callback, the stack trace of the error |
34 |
| -// will be wrapped by the stack trace of the original subscription |
35 |
| -DurianPlugins.set(RxTracingPolicy.class, new LogSubscriptionTrace()). |
36 |
| -``` |
| 66 | +* `input` - This is everything inside of INPUT (guaranteed to have only unix newlines at runtime) |
| 67 | +* `output` - The script must assign to this variable. FreshMark will generate a new string where the `INPUT` section has been replaced with this value. |
| 68 | +
|
| 69 | +Only four functions are provided: |
| 70 | +
|
| 71 | +* `link(text, url)` - returns a markdown link |
| 72 | +* `image(altText, url)` - returns a markdown image |
| 73 | +* `shield(altText, subject, status, color)` - returns a markdown image generated by [shields.io](http://shields.io/). |
| 74 | +* `prefixDelimReplace(input, prefix, delimiter, replace)` - updates URLs which contain version numbers. |
| 75 | + * example: for parameters `prefix='http://website/', delimiter='/', replace='2.0'` |
| 76 | + * input `[entry point](http://website/1.2/docs/entryPoint)` would be transformed into `[entry point](http://website/2.0/docs/entryPoint)` |
| 77 | + |
| 78 | +It's full ECMAScript 5.1, so you can define any other functions you like, but these should be all you need. |
| 79 | +
|
| 80 | +When you run FreshMark, you can supply it with a map of key-value pairs using the command line or via a properties file. If you're running FreshMark from a build system plugin such as Gradle, then all of your project's metadata will automatically be supplied. These key-value pairs are used in the following way: |
| 81 | +
|
| 82 | +* Before `PROGRAM` is executed, any `{{key}}` templates will be substituted with their corresponding value. |
| 83 | +* When `PROGRAM` is executed, all of these key-value pairs are available as variables. |
| 84 | +
|
| 85 | +## How to run it |
| 86 | +
|
| 87 | +At the moment, you can run FreshMark using [Gradle](#gradle), the [console](#console), or the [Java API](#java-api directly. If you need a different way to run FreshMark, build it and submit a PR! We'd be happy to help [in Gitter](https://gitter.im/diffplug/freshmark). |
| 88 | + |
| 89 | +### Gradle |
37 | 90 |
|
38 |
| -Lastly, DurianRx provides convenience classes for manipulating Guava's immutable collections inside reactive containers, such as `RxSet<T> extends RxBox<ImmutableSet<T>>`, which can be used as such: |
39 |
| - |
40 |
| -```java |
41 |
| -public void mouseClicked(MouseEvent e) { |
42 |
| - rxMouseOver.get().ifPresent(cell -> { |
43 |
| - Set<Integer> currentSelection = rxSelection.get(); |
44 |
| - if (e.isControlDown()) { |
45 |
| - // control => toggle mouseOver item in selection |
46 |
| - if (currentSelection.contains(cell)) { |
47 |
| - rxSelection.remove(cell); |
48 |
| - } else { |
49 |
| - rxSelection.add(cell); |
50 |
| - } |
51 |
| - } else { |
52 |
| - // no control => set selection to mouseOver |
53 |
| - rxSelection.set(Collections.singleton(cell)); |
54 |
| - } |
55 |
| - }); |
| 91 | +Integration with Gradle is provided through the [Spotless](https://github.com/diffplug/spotless) plugin. Spotless can also enforce lots of style rules as well (tab vs whitespace, Java import ordering, etc), but it's completely a-la-carte. To just apply FreshMark to all of the markdown in your project (and nothing else), simply add this to your `build.gradle`: |
| 92 | + |
| 93 | +```groovy |
| 94 | +plugins { |
| 95 | + id 'com.diffplug.gradle.spotless' version '1.4.0' |
| 96 | +} |
| 97 | +
|
| 98 | +spotless { |
| 99 | + freshmark '**/*.md' |
56 | 100 | }
|
| 101 | +``` |
| 102 | + |
| 103 | +See the [spotless docs] for more details. |
57 | 104 |
|
58 |
| -... |
| 105 | +### CLI |
| 106 | + |
| 107 | +This repo is a command line application. Just run `freshmark.bat` (Windows) or `freshmark` (Linux and Mac) to run it. |
59 | 108 |
|
60 |
| -Rx.subscribe(rxSelection, set -> { |
61 |
| - // take some action in response to |
62 |
| - // selection change |
63 |
| -}); |
64 | 109 | ```
|
| 110 | +freshmark --help |
65 | 111 |
|
66 |
| -Perhaps most useful of all is the [Immutables](https://diffplug.github.io/durian-rx/javadoc/snapshot/com/diffplug/common/rx/Immutables.html) utility class, which helps with all kinds of manipulations of Guava's immmutable collections. |
67 | 112 |
|
68 |
| -DurianRx's only requirements are [Guava](https://github.com/google/guava), [RxJava](https://github.com/reactivex/rxjava), and [Durian](https://github.com/diffplug/durian). |
| 113 | +``` |
69 | 114 |
|
70 |
| -## Acknowledgements |
| 115 | +### Java API |
71 | 116 |
|
72 |
| -* Many thanks to [RxJava](https://github.com/reactivex/rxjava) and [Guava](https://github.com/google/guava). |
73 |
| -* Stream Collectors for Guava collections inspired by [Maciej Miklas's blog post](http://blog.comsysto.com/2014/11/12/java-8-collectors-for-guava-collections/). |
74 |
| -* Formatted by [spotless](https://github.com/diffplug/spotless), [as such](https://github.com/diffplug/durian-rx/blob/v1.0/build.gradle?ts=4#L70-L90). |
| 117 | +There's just one class that really matters. If you want to add more functions, change which variables are there, make the behavior depend on the section name, etc, just take a peek at [FreshMark.java](src/main/java/com/diffplug/freshmark/FreshMark.java). |
| 118 | +
|
| 119 | +## Acknowledgements |
| 120 | +* Scripts run by [JScriptBox](https://github.com/diffplug/jscriptbox). |
75 | 121 | * Bugs found by [findbugs](http://findbugs.sourceforge.net/), [as such](https://github.com/diffplug/durian-rx/blob/v1.0/build.gradle?ts=4#L92-L116).
|
76 | 122 | * Scripts in the `.ci` folder are inspired by [Ben Limmer's work](http://benlimmer.com/2013/12/26/automatically-publish-javadoc-to-gh-pages-with-travis-ci/).
|
77 | 123 | * Built by [gradle](http://gradle.org/).
|
|
0 commit comments