• Stars
    star
    777
  • Rank 58,500 (Top 2 %)
  • Language
    Java
  • License
    MIT License
  • Created almost 10 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

True Object-Oriented Java Web Framework without NULLs, Static Methods, Annotations, and Mutable Objects

logo

EO principles respected here DevOps By Rultor.com We recommend IntelliJ IDEA

mvn Javadoc codebeat badge License Test Coverage Hits-of-Code Lines of code SonarQube Maintainability Maven Central PDD status

Takes is a true object-oriented and immutable Java8 web development framework. Its key benefits, comparing to all others, include these four fundamental principles:

  1. Not a single null (why NULL is bad?)
  2. Not a single public static method (why they are bad?)
  3. Not a single mutable class (why they are bad?)
  4. Not a single instanceof keyword, type casting, or reflection (why?)

Of course, there are no configuration files. Besides that, these are more traditional features, out of the box:

This is what is not supported and won't be supported:

These two web systems use Takes, and they are open source: wring.io (sources), jare.io (sources).

Watch these videos to learn more: An Immutable Object-Oriented Web Framework and Takes, Java Web Framework, Intro. This blog post may help you too.

Contents

Quick Start

Create this App.java file:

import org.takes.http.Exit;
import org.takes.http.FtBasic;
import org.takes.facets.fork.FkRegex;
import org.takes.facets.fork.TkFork;
public final class App {
  public static void main(final String... args) throws Exception {
    new FtBasic(
      new TkFork(new FkRegex("/", "hello, world!")), 8080
    ).start(Exit.NEVER);
  }
}

Then, download takes.jar and compile your Java code:

$ javac -cp takes.jar App.java

Now, run it like this:

$ java -Dfile.encoding=UTF-8 -cp takes.jar:. App

Should work :)

This code starts a new HTTP server on port 8080 and renders a plain-text page on all requests at the root URI.

Important: Pay attention that UTF-8 encoding is set on the command line. The entire framework relies on your default Java encoding, which is not necessarily UTF-8 by default. To be sure, always set it on the command line with file.encoding Java argument. We decided not to hard-code "UTF-8" in our code mostly because this would be against the entire idea of Java localization, according to which a user always should have a choice of encoding and language selection. We're using Charset.defaultCharset() everywhere in the code.

Build and Run With Maven

If you're using Maven, this is how your pom.xml should look like:

<project>
  <dependencies>
    <dependency>
      <groupId>org.takes</groupId>
      <artifactId>takes</artifactId>
    </dependency>
  </dependencies>
  <profiles>
    <profile>
      <id>hit-refresh</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.3</version>
            <executions>
              <execution>
                <id>start-server</id>
                <phase>pre-integration-test</phase>
                <goals>
                  <goal>java</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <mainClass>foo.App</mainClass> <!-- your main class -->
              <cleanupDaemonThreads>false</cleanupDaemonThreads>
              <arguments>
                <argument>--port=${port}</argument>
              </arguments>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
</project>

With this configuration you can run it from command line:

$ mvn clean integration-test -Phit-refresh -Dport=8080

Maven will start the server and you can see it at http://localhost:8080.

Using in servlet app

Create a take with constructor accepting ServletContext:

package com.myapp;

public final class TkApp implements Take {
  private final ServletContext ctx;

  public TkApp(final ServletContext context) {
    this.ctx = context;
  }

  @Override
  public Response act(final Request req) throws Exception {
    return new RsText("Hello servlet!");
  }
}

Add org.takes.servlet.SrvTake to your web.xml, don't forget to specify take class as servlet init-param:

  <servlet>
    <servlet-name>takes</servlet-name>
    <servlet-class>org.takes.servlet.SrvTake</servlet-class>
    <init-param>
      <param-name>take</param-name>
      <param-value>com.myapp.TkApp</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>takes</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

Build and Run With Gradle

If you're using Gradle, this is how your build.gradle should look like:

plugins {
    id 'java'
    id 'application'
}

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.takes', name: 'takes', version: '1.11.3'
}

mainClassName='foo.App' //your main class

With this configuration you can run it from command line:

$ gradle run -Phit-refresh -Dport=8080

Unit Testing

This is how you can unit test the app, using JUnit 4.x and Hamcrest:

public final class AppTest {
  @Test
  public void returnsHttpResponse() throws Exception {
    MatcherAssert.assertThat(
      new RsPrint(
        new App().act(new RqFake("GET", "/"))
      ).printBody(),
      Matchers.equalsTo("hello, world!")
    );
  }
}

You can create a fake request with form parameters like this:

new RqForm.Fake(
  new RqFake(),
  "foo", "value-1",
  "bar", "value-2"
)

Integration Testing

Here is how you can test the entire server via HTTP, using JUnit and jcabi-http for making HTTP requests:

public final class AppITCase {
  @Test
  public void returnsTextPageOnHttpRequest() throws Exception {
    new FtRemote(new App()).exec(
      new FtRemote.Script() {
        @Override
        public void exec(final URI home) throws IOException {
          new JdkRequest(home)
            .fetch()
            .as(RestResponse.class)
            .assertStatus(HttpURLConnection.HTTP_OK)
            .assertBody(Matchers.equalTo("hello, world!"));
        }
      }
    );
  }
}

More complex integration testing examples you can find in one of the open source projects that are using Take, for example: rultor.com.

A Bigger Example

Let's make it a bit more sophisticated:

public final class App {
  public static void main(final String... args) {
    new FtBasic(
      new TkFork(
        new FkRegex("/robots\\.txt", ""),
        new FkRegex("/", new TkIndex())
      ),
      8080
    ).start(Exit.NEVER);
  }
}

The FtBasic is accepting new incoming sockets on port 8080, parses them according to HTTP 1.1 specification and creates instances of class Request. Then, it gives requests to the instance of TkFork (tk stands for "take") and expects it to return an instance of Take back. As you probably understood already, the first regular expression that matches returns a take. TkIndex is our custom class, let's see how it looks:

public final class TkIndex implements Take {
  @Override
  public Response act(final Request req) {
    return new RsHtml("<html>Hello, world!</html>");
  }
}

It is immutable and must implement a single method act(), which is returning an instance of Response. So far so good, but this class doesn't have an access to an HTTP request. Here is how we solve this:

new TkFork(
  new FkRegex(
    "/file/(?<path>[^/]+)",
    new TkRegex() {
      @Override
      public Response act(final RqRegex request) throws Exception {
        final File file = new File(
          request.matcher().group("path")
        );
        return new RsHTML(
          FileUtils.readFileToString(file, Charsets.UTF_8)
        );
      }
    }
  )
)

We're using TkRegex instead of Take, in order to deal with RqRegex instead of a more generic Request. RqRegex gives an instance of Matcher used by FkRegex for pattern matching.

Here is a more complex and verbose example:

public final class App {
  public static void main(final String... args) {
    new FtBasic(
      new TkFork(
        new FkRegex("/robots.txt", ""),
        new FkRegex("/", new TkIndex()),
        new FkRegex(
          "/xsl/.*",
          new TkWithType(new TkClasspath(), "text/xsl")
        ),
        new FkRegex("/account", new TkAccount(users)),
        new FkRegex("/balance/(?<user>[a-z]+)", new TkBalance())
      )
    ).start(Exit.NEVER);
  }
}

Front interface

Essential part of Bigger Example is Front interface. It's encapsulates server's back-end and used to start an instance, which will accept requests and return results. FtBasic, which is a basic front, implements that interface - you've seen it's usage in above mentioned example.

There are other useful implementations of this interface:

Back interface

Back interface is the back-end that is responsible for IO operations on TCP network level. There are various useful implementations of that interface:

  • The BkBasic class is a basic implementation of the Back interface. It is responsible for accepting the request from Socket, converting the socket's input to the Request, dispatching it to the provided Take instance, getting the result and printing it to the socket's output until all the request is fulfilled.
  • The BkParallel class is a decorator of the Back interface, that is responsible for running the back-end in parallel threads. You can specify the number of threads or try to use the default number, which depends on available processors number in JVM.
  • The BkSafe class is a decorator of the Back interface, that is responsible for running the back-end in a safe mode. That means that it will ignore exception thrown from original Back.
  • The BkTimeable class is a decorator of the Back interface, that is responsible for running the back-end for specified maximum lifetime in milliseconds. It is constantly checking if the thread with original back exceeds provided limit and if so - it's interrupts the thread of that back.
  • The BkWrap class is a convenient wrap over the original Back instance. It's just delegates the accept to that Back and might be useful if you want to add your own decorators of the Back interface. This class is used in BkParallel and BkSafe as a parent class.

Templates

Now let's see how we can render something more complex than a plain text. First, XML+XSLT is a recommended mechanism of HTML rendering. Even though it may be too complex, give it a try, you won't regret. Here is how we render a simple XML page that is transformed to HTML5 on-fly (more about RsXembly read below):

public final class TkAccount implements Take {
  private final Users users;
  public TkAccount(final Users users) {
    this.users = users;
  }
  @Override
  public Response act(final Request req) {
    final User user = this.users.find(new RqCookies(req).get("user"));
    return new RsLogin(
      new RsXslt(
        new RsXembly(
          new XeStylesheet("/xsl/account.xsl"),
          new XeAppend("page", user)
        )
      ),
      user
    );
  }
}

This is how that User class may look like:

public final class User implements XeSource {
  private final String name;
  private final int balance;
  @Override
  public Iterable<Directive> toXembly() {
    return new Directives().add("user")
      .add("name").set(this.name).up()
      .add("balance").set(Integer.toString(this.balance));
  }
}

Here is how RsLogin may look like:

public final class RsLogin extends RsWrap {
  public RsLogin(final Response response, final User user) {
    super(
      new RsWithCookie(
        response, "user", user.toString()
      )
    );
  }
}

Velocity Templates

Let's say, you want to use Velocity:

public final class TkHelloWorld implements Take {
  @Override
  public Response act(final Request req) {
    return new RsVelocity(
      "hi, ${user.name}! You've got ${user.balance}",
      new RsVelocity.Pair("user", new User())
    );
  }
}

You will need this extra dependency in classpath:

<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity-engine-core</artifactId>
  <scope>runtime</scope>
</dependency>

For Gradle users:

dependencies {
    ...
    runtime group: 'org.apache.velocity', name: 'velocity-engine-core', version: 'x.xx'//put the version here
    ...
}

Static Resources

Very often you need to serve static resources to your web users, like CSS stylesheets, images, JavaScript files, etc. There are a few supplementary classes for that:

new TkFork(
  new FkRegex("/css/.+", new TkWithType(new TkClasspath(), "text/css")),
  new FkRegex("/data/.+", new TkFiles(new File("/usr/local/data"))
)

Class TkClasspath take static part of the request URI and finds a resource with this name in classpath.

TkFiles just looks by file name in the directory configured.

TkWithType sets content type of all responses coming out of the decorated take.

Hit Refresh Debugging

It is a very convenient feature. Once you start the app you want to be able to modify its static resources (CSS, JS, XSL, etc), refresh the page in a browser and immediately see the result. You don't want to re-compile the entire project and restart it. Here is what you need to do to your sources in order to enable that feature:

new TkFork(
  new FkRegex(
    "/css/.+",
    new TkWithType(
      new TkFork(
        new FkHitRefresh(
          "./src/main/resources/foo/scss/**", // what sources to watch
          "mvn sass:compile", // what to run when sources are modified
          new TkFiles("./target/css")
        )
        new FkFixed(new TkClasspath())
      ),
      "text/css"
    )
  )
)

This FkHitRefresh fork is a decorator of take. Once it sees X-Take-Refresh header in the request, it realizes that the server is running in "hit-refresh" mode and passes the request to the encapsulated take. Before it passes the request it tries to understand whether any of the resources are older than compiled files. If they are older, it tries to run compilation tool to build them again.

Request Methods (POST, PUT, HEAD, etc.)

Here is an example:

new TkFork(
  new FkRegex(
    "/user",
    new TkFork(
      new FkMethods("GET", new TkGetUser()),
      new FkMethods("POST,PUT", new TkPostUser()),
      new FkMethods("DELETE", new TkDeleteUser())
    )
  )
)

Request Parsing

Here is how you can parse an instance of Request:

Href href = new RqHref.Base(request).href();
URI uri = href.uri();
Iterable<String> values = href.param("key");

For a more complex parsing try to use Apache Http Client or something similar.

Form Processing

Here is an example:

public final class TkSavePhoto implements Take {
  @Override
  public Response act(final Request req) {
    final String name = new RqForm(req).param("name");
    return new RsWithStatus(HttpURLConnection.HTTP_NO_CONTENT);
  }
}

Exception Handling

By default, TkFork lets all exceptions bubble up. If one of your take crashes, a user will see a default error page. Here is how you can configure this behavior:

public final class App {
  public static void main(final String... args) {
    new FtBasic(
      new TkFallback(
        new TkFork(
          new FkRegex("/robots\\.txt", ""),
          new FkRegex("/", new TkIndex())
        ),
        new FbChain(
          new FbStatus(404, new RsText("sorry, page is absent")),
          new FbStatus(405, new RsText("this method is not allowed here")),
          new Fallback() {
            @Override
            public Iterator<Response> route(final RqFallback req) {
              return Collections.<Response>singleton(
                new RsHTML("oops, something went terribly wrong!")
              ).iterator();
            }
          }
        )
      ),
      8080
    ).start(Exit.NEVER);
  }
}

TkFallback decorates an instance of Take and catches all exceptions any of its take may throw. Once it's thrown, an instance of FbChain will find the most suitable fallback and will fetch a response from there.

Redirects

Sometimes it's very useful to return a redirect response (30x status code), either by a normal return or by throwing an exception. This example illustrates both methods:

public final class TkPostMessage implements Take {
  @Override
  public Response act(final Request req) {
    final String body = new RqPrint(req).printBody();
    if (body.isEmpty()) {
      throw new RsForward(
        new RsFlash("message can't be empty")
      );
    }
    // save the message to the database
    return new RsForward(
      new RsFlash(
        "thanks, the message was posted"
      ),
      "/"
    );
  }
}

Then, you should decorate the entire TkFork with this TkForward and TkFlash:

public final class App {
  public static void main(final String... args) {
    new FtBasic(
      new TkFlash(
        new TkForward(
          new TkFork(new FkRegex("/", new TkPostMessage())
        )
      ),
      8080
    ).start(Exit.NEVER);
  }
}

RsJSON

Here is how we can deal with JSON:

public final class TkBalance extends TkFixed {
  @Override
  public Response act(final RqRegex request) {
    return new RsJSON(
      new User(request.matcher().group("user")))
    );
  }
}

This is the method to add to User:

public final class User implements XeSource, RsJSON.Source {
  @Override
  public JsonObject toJSON() {
    return Json.createObjectBuilder()
      .add("balance", this.balance)
      .build();
  }
}

RsXembly

Here is how you generate an XML page using Xembly:

Response response = new RsXembly(
  new XeAppend("page"),
  new XeDirectives("XPATH '/page'", this.user)
)

This is a complete example, with all possible options:

Response response = new RsXembly(
  new XeStylesheet("/xsl/account.xsl"), // add processing instruction
  new XeAppend(
    "page", // create a DOM document with "page" root element
    new XeMillis(false), // add "millis" attribute to the root, with current time
    user, // add user to the root element
    new XeSource() {
      @Override
      public Iterable<Directive> toXembly() {
        return new Directives().add("status").set("alive");
      }
    },
    new XeMillis(true), // replace "millis" attribute with take building time
  ),
)

This is the output that will be produced:

<?xml version='1.0'?>
<?xsl-stylesheet href='/xsl/account.xsl'?>
<page>
  <millis>5648</millis>
  <user>
    <name>Jeff Lebowski</name>
    <balance>123</balance>
  </user>
  <status>alive</status>
</page>

To avoid duplication of all this scaffolding in every page, you can create your own class, which will be used in every page, for example:

Response response = new RsXembly(
  new XeFoo(user)
)

This is how this XeFoo class would look like:

public final class XeFoo extends XeWrap {
  public XeFoo(final String stylesheet, final XeSource... sources) {
    super(
      new XeAppend(
        "page",
        new XeMillis(false),
        new XeStylesheet(stylesheet),
        new XeChain(sources),
        new XeSource() {
          @Override
          public Iterable<Directive> toXembly() {
            return new Directives().add("status").set("alive");
          }
        },
        new XeMillis(true)
      )
    );
  }
}

You will need this extra dependency in classpath:

<dependency>
  <groupId>com.jcabi.incubator</groupId>
  <artifactId>xembly</artifactId>
</dependency>

More about this mechanism in this blog post: XML Data and XSL Views in Takes Framework.

Cookies

Here is how we drop a cookie to the user:

public final class TkIndex implements Take {
  @Override
  public Response act(final Request req) {
    return new RsWithCookie("auth", "John Doe");
  }
}

An HTTP response will contain this header, which will place a auth cookie into the user's browser:

HTTP/1.1 200 OK
Set-Cookie: auth="John Doe"

This is how you read cookies from a request:

public final class TkIndex implements Take {
  @Override
  public Response act(final Request req) {
    // the list may be empty
    final Iterable<String> cookies = new RqCookies(req).cookie("my-cookie");
  }
}

GZIP Compression

If you want to compress all your responses with GZIP, wrap your take in TkGzip:

new TkGzip(take)

Now, each request that contains Accept-Encoding request header with gzip compression method inside will receive a GZIP-compressed response. Also, you can compress an individual response, using RsGzip decorator.

Content Negotiation

Say, you want to return different content based on Accept header of the request (a.k.a. content negotiation):

public final class TkIndex implements Take {
  @Override
  public Response act(final Request req) {
    return new RsFork(
      req,
      new FkTypes("text/*", new RsText("it's a text"))
      new FkTypes("application/json", new RsJSON("{\"a\":1}"))
      new FkTypes("image/png", /* something else */)
    );
  }
}

SSL Configuration

First of all, setup your keystore settings, for example

final String file = this.getClass().getResource("/org/takes/http/keystore").getFile();
final String password = "abc123";
System.setProperty("javax.net.ssl.keyStore", file);
System.setProperty("javax.net.ssl.keyStorePassword", password);
System.setProperty("javax.net.ssl.trustStore", file);
System.setProperty("javax.net.ssl.trustStorePassword", password);

Then simple create exemplar of class FtSecure with socket factory

final ServerSocket skt = SSLServerSocketFactory.getDefault().createServerSocket(0);
new FtRemote(
  new FtSecure(new BkBasic(new TkFixed("hello, world")), skt),
  skt,
  true
);

Authentication

Here is an example of login via Facebook:

new TkAuth(
  new TkFork(
    new FkRegex("/", new TkHTML("hello, check <a href='/acc'>account</a>")),
    new FkRegex("/acc", new TkSecure(new TkAccount()))
  ),
  new PsChain(
    new PsCookie(
      new CcSafe(new CcHex(new CcXOR(new CcCompact(), "secret-code")))
    ),
    new PsByFlag(
      new PsByFlag.Pair(
        PsFacebook.class.getSimpleName(),
        new PsFacebook("facebook-app-id", "facebook-secret")
      ),
      new PsByFlag.Pair(
        PsLogout.class.getSimpleName(),
        new PsLogout()
      )
    )
  )
)

Then, you need to show a login link to the user, which he or she can click and get to the Facebook OAuth authentication page. Here is how you do this with XeResponse:

new RsXembly(
  new XeStylesheet("/xsl/index.xsl"),
  new XeAppend(
    "page",
    new XeFacebookLink(req, "facebook-app-id"),
    // ... other xembly sources
  )
)

The link will be add to the XML page like this:

<page>
  <links>
    <link rel="take:facebook" href="https://www.facebook.com/dialog/oauth..."/>
  </links>
</page>

Similar mechanism can be used for PsGithub, PsGoogle, PsLinkedin, PsTwitter, etc.

This is how you get currently logged in user:

public final class TkAccount implements Take {
  @Override
  public Response act(final Request req) {
    final Identity identity = new RqAuth(req).identity();
    if (this.identity.equals(Identity.ANONYMOUS)) {
      // returns "urn:facebook:1234567" for a user logged in via Facebook
      this.identity().urn();
    }
  }
}

More about it in this blog post: How Cookie-Based Authentication Works in the Takes Framework

Command Line Arguments

There is a convenient class FtCLI that parses command line arguments and starts the necessary Front accordingly.

There are a few command line arguments that should be passed to FtCLI constructor:

--port=1234         Tells the server to listen to TCP port 1234
--lifetime=5000     The server will die in five seconds (useful for integration testing)
--hit-refresh       Run the server in hit-refresh mode
--daemon            Runs the server in Java daemon thread (for integration testing)
--threads=30        Processes incoming HTTP requests in 30 parallel threads
--max-latency=5000  Maximum latency in milliseconds per each request
                    (longer requests will be interrupted)

For example:

public final class App {
  public static void main(final String... args) {
    new FtCLI(
      new TkFork(new FkRegex("/", "hello, world!")),
      args
    ).start(Exit.NEVER);
  }
}

Then, run it like this:

$ java -cp take.jar App.class --port=8080 --hit-refresh

You should see "hello, world!" at http://localhost:8080.

Parameter --port also accepts file name, instead of a number. If the file exists, FtCLI will try to read its content and use it as port number. If the file is absent, FtCLI will allocate a new random port number, use it to start a server, and save it to the file.

Logging

The framework sends all logs to SLF4J logging facility. If you want to see them, configure one of SLF4J bindings.

To make a Take log, wrap it in a TkSlf4j - for example:

 new TkSlf4j(
     new TkFork(...)
 )

Directory Layout

You are free to use any build tool, but we recommend Maven. This is how your project directory layout may/should look like:

/src
  /main
    /java
      /foo
        App.java
    /scss
    /coffeescript
    /resources
      /vtl
      /xsl
      /js
      /css
      robot.txt
      log4j.properties
  /test
    /java
      /foo
        AppTest.java
    /resources
      log4j.properties
pom.xml
LICENSE.txt

Optional dependencies

If you're using Maven and include Takes as a dependency in your own project, you can choose which of the optional dependencies to include in your project. The list of all of the optional dependencies can be seen in the Takes project pom.xml.

For example, to use the Facebook API shown above, simply add a dependency to the restfb API in your project:

<dependency>
  <groupId>com.restfb</groupId>
  <artifactId>restfb</artifactId>
  <version>1.15.0</version>
  <scope>runtime</scope>
</dependency>

For Gradle, you should add the dependencies as usual:

dependencies {
    ...
    runtime group: 'com.restfb', name: 'restfb', version: '1.15.0'
}

Backward compatibility

Version 2.0 is not backward compatible with previous versions.

Version pattern for RESTful API

The URL should NOT contain the versions, but the type requested.

For example:

===>
GET /architect/256 HTTP/1.1
Accept: application/org.takes.architect-v1+xml
<===
HTTP/1.1 200 OK
Content-Type: application/org.takes.architect-v1+xml
<architect>
  <name>Yegor Bugayenko</name>
</architect>

Then clients aware of newer version of this service can call:

===>
GET /architect/256 HTTP/1.1
Accept: application/org.takes.architect-v2+xml
<===
HTTP/1.1 200 OK
Content-Type: application/org.takes.architect-v2+xml

<architect>
  <firstName>Yegor</firstName>
  <lastName>Bugayenko</lastName>
  <salutation>Mr.</salutation>
</architect>

This article explains why itΒ΄s done this way.

How to contribute

Fork repository, make changes, send us a pull request. We will review your changes and apply them to the master branch shortly, provided they don't violate our quality standards. To avoid frustration, before sending us your pull request please run full Maven build:

$ mvn clean install -Pqulice

To avoid build errors use maven 3.2+.

Pay attention that our pom.xml inherits a lot of configuration from jcabi-parent. This article explains why it's done this way.

More Repositories

1

tacit

CSS framework for dummies, without a single CSS class: nicely renders properly formatted HTML5 pages
SCSS
1,694
star
2

cactoos

Object-Oriented Java primitives, as an alternative to Google Guava and Apache Commons
Java
737
star
3

rultor

DevOps team assistant that helps you merge, deploy, and release GitHub-hosted apps and libraries
Java
468
star
4

qulice

Quality Police for Java projects: aggregator of Checkstyle and PMD
Java
301
star
5

s3auth

Amazon S3 HTTP Basic Auth Gateway: put your files into S3 bucket and make them accessible with a login/password through a browser
Java
254
star
6

xembly

Assembly for XML: an imperative language for modifying XML documents
Java
237
star
7

jare

Free and Instant Content Delivery Network (CDN)
Java
130
star
8

elegantobjects.github.io

Fan club for Elegant Objects programmers
HTML
111
star
9

iri

Simple Immutable URI/URL Builder in Ruby
Ruby
110
star
10

0pdd

Puzzle Driven Development (PDD) Chatbot Assistant for Your GitHub Repositories
Ruby
109
star
11

blog

My blog about computers, written in Jekyll and deployed to GitHub Pages
Liquid
108
star
12

quiz

Refactor the code to make it look more object-oriented and maintainable
PHP
104
star
13

dynamo-archive

Archive and Restore DynamoDB Tables, from the Command Line
JavaScript
100
star
14

jekyll-github-deploy

Jekyll Site Automated Deployer to GitHub Pages
Ruby
78
star
15

sixnines

Website Availability Monitor: add your website to our dashboard and get 24x7 monitoring of its availability (and a badge!)
Ruby
68
star
16

hoc

Hits-of-Code Command Line Calculator, for Git and Subversion
Ruby
61
star
17

ssd16

16 lectures about "Software Systems Design" presented in Innopolis University in 2021 for 3rd year BSc students
TeX
57
star
18

squid-proxy

Docker image for a Squid forward proxy with authorization (fully anonymous)
Dockerfile
52
star
19

jekyll-plantuml

PlantUML plugin for Jekyll: helps you embed UML diagrams into static pages
Ruby
43
star
20

xdsd

eXtremely Distributed Software Development
TeX
41
star
21

jpages

Experimental Java OOP Web Framework
Java
39
star
22

rehttp

HTTP Repeater: you point your Webhooks to us and we make sure they get delivered even if not on the first try
Java
39
star
23

netbout

Private talks made easy
Java
39
star
24

awesome-risks

Sample Risks for a Software Project
38
star
25

requs

Controlled Natural Language for Requirements Specifications
Java
37
star
26

cactoos-http

Object-Oriented HTTP Client
Java
36
star
27

threecopies

Hosted Server Backup Service
Java
36
star
28

awesome-academic-oop

Curated list of academic writings on object-oriented programming
35
star
29

threads

Ruby Gem to unit-test a piece of code in multiple concurrent threads
Ruby
35
star
30

zache

Zero-footprint Ruby In-Memory Thread-Safe Cache
Ruby
34
star
31

codexia

Open Source Incubator
Ruby
33
star
32

mailanes

Smart E-mail Delivery System
Ruby
33
star
33

micromap

πŸ“ˆ A much faster (for very small maps!) alternative of Rust HashMap, which doesn't use hashing and doesn't use heap
Rust
31
star
34

hangman

Hangman (the game) written in a very unelegant procedural style, which you can improve in order to test your skills
Java
29
star
35

wring

Smart Inbox for GitHub Notifications
Java
29
star
36

jacli

Java Command Line Interface
29
star
37

sibit

Simplified Command-Line Bitcoin Client
Ruby
27
star
38

xcop

Command Line Style Checker of XML Documents
Ruby
27
star
39

phprack

phpRack Integration Testing Framework
PHP
25
star
40

thindeck

Web Hosting That Deploys Itself
Java
24
star
41

elegantobjects

Supplementary materials for "Elegant Objects" book
Java
22
star
42

jekyll-git-hash

Jekyll Plugin for Git Hash Retrieval
Ruby
21
star
43

painofoop

Object-oriented programming is a pain if we do it wrong: Lecture Notes for a BSc course
TeX
21
star
44

0rsk

Online Risk Manager
Ruby
20
star
45

tojos

Text Object Java Objects (TOJOs): an object representation of a multi-line structured text file like CSV, YAML, or JSON
Java
19
star
46

soalition

Social Coalitions of Internet Writers
Ruby
18
star
47

random-port

A Ruby gem to reserve a random TCP port
Ruby
17
star
48

jo

Junior Objects: JavaScript Examples
JavaScript
17
star
49

latex-best-practices

A short collection of LaTeX academic writing best practices: it's my personal taste, read it skeptically
TeX
17
star
50

total

Ruby Gem to get total memory size in the system
Ruby
16
star
51

backtrace

Ruby gem to print exception backtrace nicely
Ruby
16
star
52

telepost

Simple Telegram posting Ruby gem
Ruby
15
star
53

rexsl

Java RESTful XSL-based Web Framework
Java
15
star
54

ru.yegor256.com

My Russian blog about politics and social problems
HTML
15
star
55

huawei.cls

LaTeX class for documents you create when working with Huawei or maybe even inside it
TeX
14
star
56

glogin

Login/logout via GitHub OAuth for your Ruby web app
Ruby
14
star
57

use_tinymce

yet another TinyMCE for Rails adaptor. Rails 3 + Minimal dependencies
JavaScript
14
star
58

tacky

Primitive Object Memoization for Ruby
Ruby
14
star
59

nutch-in-java

How to use Apache Nutch without command line
Java
14
star
60

futex

File-based Ruby Mutex
Ruby
14
star
61

seedramp

Micro-Investment Venture Fund
HTML
14
star
62

veils

Ruby Veil Objects
Ruby
13
star
63

texsc

Spell checking for LaTeX documents with the help of aspell
Ruby
13
star
64

bloghacks

Jekyll demo blog for "256 Bloghacks" book
HTML
13
star
65

cam

Classes and Metriсs (CaM): a dataset of Java classes from public open-source GitHub repositories
Shell
13
star
66

latexmk-action

GitHub action for building LaTeX documents via latexmk
Dockerfile
13
star
67

rumble

Command Line Tool to Send Newsletters
Ruby
13
star
68

est

Estimates Automated
Ruby
12
star
69

techiends

Tech Friends Club
HTML
12
star
70

syncem

A simple Ruby decorator to make all methods of your object thread-safe
Ruby
12
star
71

loog

Ruby object, which you can pass to other objects, where they will use it as a logger
Ruby
12
star
72

fibonacci

Fibonacci algorithm implemented in a few compilable languages in different programming flavors
C++
12
star
73

drops

Primitive CSS classes to replace most commonly used CSS styles
CSS
12
star
74

kdpcover

LaTeX class rendering a cover for a book published by Kindle Direct Publishing (KDP)
TeX
12
star
75

iccq.github.io

Official Website of International Conference on Code Quality (ICCQ)
TeX
12
star
76

ppt-slides

LaTeX package for making slide decks Γ  la PowerPoint (PPT)
TeX
12
star
77

dockers

Useful Docker Images
Dockerfile
11
star
78

obk

Ruby decorator to throttle object method calls: there will be fixed delays between them
Ruby
11
star
79

microstack

The most primitive and the fastest implementation of a fixed-size last-in-first-out stack on stack in Rust, for Copy-implementing types
Rust
11
star
80

jaxec

Primitive execution of command line commands from Java (mostly useful for tests)
Java
11
star
81

xsline

Declarative and Immutable Java Chain of XSL Transformations
Java
11
star
82

jekyll-chatgpt-translate

Automated translating of Jekyll pages via ChatGPT: all you need is just an OpenAI API key
Ruby
10
star
83

tdx

Test Dynamics
Ruby
10
star
84

phandom

PhantomJS Java DOM Builder
Java
10
star
85

texqc

LaTeX Build Quality Control: checks the log file after LaTeX and finds error reports
Ruby
10
star
86

random-tcp-port

Random TCP Port Reserver
C++
10
star
87

names-vs-complexity

How compound variable names affect complexity of Java methods
TeX
10
star
88

jekyll-bits

Jekyll plugin with simple and nice tools for better blogging
Ruby
10
star
89

articles

Some articles I write for online and offline magazines
Perl
9
star
90

bibrarian

Quotes Organized
Java
9
star
91

jpeek-maven-plugin

Maven Plugin for jPeek
Java
9
star
92

yb-book

This LaTeX class I'm using for all my books I publish on Amazon
TeX
9
star
93

size-vs-immutability

Empirically proven that immutable Java classes are smaller than mutable ones
TeX
9
star
94

rultor-image

Default Docker image for Rultor
Dockerfile
9
star
95

rultor-remote

Rultor command line remote control
Ruby
9
star
96

emap

πŸ“ˆ The fastest map possible in Rust, where keys are integers and the capacity is fixed (faster than Vec!)
Rust
9
star
97

colorizejs

jQuery plugin to colorize data elements
JavaScript
9
star
98

pgtk

PostgreSQL ToolKit for Ruby apps: Liquibase + Rake + Connection Pool
Ruby
8
star
99

fazend-framework

FaZend Framework, Zend Framework extensions
PHP
8
star
100

sqm

Lecture Notes for "Software Quality Metrics" course in HSE University, 2023-2024
TeX
8
star