Skip to content

Commit

Permalink
Fix conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
cblage committed Jan 1, 2021
2 parents 1099320 + 845e2cd commit b3fd56e
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 317 deletions.
35 changes: 25 additions & 10 deletions .travis.yml
@@ -1,27 +1,42 @@
env:
global:
- CC_TEST_REPORTER_ID=a669f9b84dcb893c8df72d85c56658c03e59c523ef619714d37b6523d35698aa
language: elixir
env: MIX_ENV=test
notifications:
recipients:
- carlos@carloslage.net
elixir:
- 1.6
email:
recipients:
- carlos@carloslage.net
language: elixir
matrix:
include:
- elixir: "1.7"
otp_release: "19.0"
- elixir: "1.8"
otp_release: "20.0"
- elixir: "1.9"
otp_release: "20.0"
- elixir: "1.10"
otp_release: "21.0"
- elixir: "1.10"
otp_release: "22.0"
- elixir: "1.10"
otp_release: "23.0"
- elixir: "1.11"
otp_release: "21.0"
- elixir: "1.11"
otp_release: "22.0"
- elixir: "1.11"
otp_release: "23.0"
before_script:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
- ./cc-test-reporter before-build
script:
- mix dialyzer
- MIX_ENV=test mix dialyzer
- MIX_ENV=test mix test
after_script:
- mix deps.get --only docs
- MIX_ENV=docs mix inch.report
- MIX_ENV=test mix credo --strict
- MIX_ENV=test mix coveralls --verbose
- MIX_ENV=test mix coveralls.json --verbose
- MIX_ENV=test mix coveralls.travis
- ./cc-test-reporter after-build -r "$CC_TEST_REPORTER_ID" -t excoveralls --exit-code $TRAVIS_TEST_RESULT
after_success:
- mix credo --strict
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -8,3 +8,4 @@ Milan Jaric <milan.jaric@gmail.com> (https://github.com/mjaric)
Nikita Kuznetsov <me@daedalus.ru>
Wes Oldenbeuving <narnach@me.com>
Vincent Siliakus <vincent@usendes.nl>
ryosan-470 (rskjtwp@gmail.com) (https://github.com/ryosan-470)
191 changes: 11 additions & 180 deletions README.md
@@ -1,195 +1,25 @@
# Elixir JSON
# [Elixir JSON](https://hex.pm/packages/json)

[![Build Status](https://travis-ci.org/cblage/elixir-json.svg?branch=master)](https://travis-ci.org/cblage/elixir-json) [![Hex.pm](https://img.shields.io/hexpm/dt/json.svg?style=flat-square)](https://hex.pm/packages/json) [![Coverage Status](https://coveralls.io/repos/github/cblage/elixir-json/badge.svg?branch=master)](https://coveralls.io/github/cblage/elixir-json?branch=master) [![Hex.pm](https://img.shields.io/hexpm/v/json.svg?style=flat-square)](https://hex.pm/packages/json) [![Inline docs](http://inch-ci.org/github/cblage/elixir-json.svg)](http://inch-ci.org/github/cblage/elixir-json)

This library provides a natively implemented JSON encoder and decoder for Elixir.

All contributions are welcome.
=======

# Before you install

When dealing with smaller `file.json ~ 14KB` payloads, `JSON v1` handles the processing consistently performant, with
a much smaller deviation, and absolutely no real-world absolute performance differences with `Jason`.

However, with often unusually large `file.json > 5MB` payloads, and if the processing speed for those payloads is
paramount to you (ie, processing them in a real-time manner vs using them in migration scripts or whatever), `JSON v1`
currently significantly slower when compared to `Jason`.

#### Small payload `bench/data/utf-8-unescaped.json < 30KB` benchmark results for `JSON v1` and `Jason`

As you can see below, both libraries handle "regular" small `json` payloads beautifully.

`JSON.decode` calls while usually being a bit slower than their `Jason` counterparts, they are more consistently
performant, with a much smaller deviation.

So I would actually advise using `JSON.decode` and `JSON.encode` for smaller payloads.

For `JSON.encode` vs `Jason.encode`, the difference is so minimal, it's not worth arguing about.

| Library | Average | Deviation | median | minimum | maximum |
|---------------- |---------- |----------- |---------- |---------- |----------- |
| `JSON.decode` | 13.35 ms | ±45.95% | 11.47 ms | 8.17 ms | 99.49 ms |
| `Jason.decode` | 0.26 ms | ±246.84% | 0.170 ms | 0.150 ms | 64.35 ms |
| `JSON.encode` | 1.32 ms | ±225.81% | 0.58 ms | 0.28 ms | 103.70 ms |
| `Jason.encode` | 0.30 ms | ±316.71% | 0.163 ms | 0.147 ms | 82.68 ms |

#### Full `benchee` reports for `bench/data/utf-8-unescaped.json < 30KB`:
- `decode`: https://bit.ly/2GVV8dy
- `encode`: https://bit.ly/2v5W0H0


#### Large payload `bench/data/issue-90.json ~ 8MB` benchmark results for `JSON v1` and `Jason`

However, with often unusually large `file.json > 5MB` payloads, and if the processing speed for those payloads is paramount to you
(ie, processing them in a real-time manner vs using them in migration scripts or whatever), then
`JSON v1` would not be the best choice when compared to `Jason`.

| Library | Average | Deviation | median | minimum | maximum |
|---------------- |---------- |----------- |---------- |---------- |----------- |
| `JSON.decode` | 8.93 s | ±5.71% | 8.96 s | 8.10 s | 9.57 s |
| `Jason.decode` | 0.182 s | ±21.60% | 0.171 s | 0.139 s | 0.42 s |
| `JSON.encode` | 5.51 s | ±18.10% | 5.24 s | 4.32 s | 7.36 s |
| `Jason.encode` | 0.186 s | ±26.41% | 0.173 s | 0.122 s | 0.38 s |

### Full `benchee` reports for `bench/data/issue-90.json ~ 8MB`:
- `decode`: https://bit.ly/2HxReEP
- `encode`: https://bit.ly/2HuR0OM

# Plan of action for `Elixir JSON v2`

I am currently working on a solution for this problem in `JSON v2`.
You can follow the process here: https://github.com/cblage/elixir-json/pull/52

# Interim Solution

To processes these large payloads adding the `Jason` lib to your dependencies (without hopefully removing `JSON`
for the smaller payloads :sweat_smile:):
- `Jason@Hex.pm`: http://hex.pm/packages/jason
- `Jason@GitHub`: https://github.com/michalmuskala/jason

After installing `Jason`, you then use `JSON.decode` and `JSON.encode` for small your small `30KB range json` payloads due to the reasons mentioned above.

While `Elixir JSON v2` is not ready to processs the bigger `>5MB json` payloads in time-sensitive operations, you go for `Jason.decode` and `Jason.encode`.

Thanks for the comprehension,
Carlos Brito Lage

## Example

```elixir
[
{:cowboy, "~> 1.0.0"},
{:plug, "~> 1.0"},
{:json, "~> 1.2"},
{:jason, "~> 1.0"},
]
```

You can find its documentation here: https://hexdocs.pm/jason/readme.html

# Before you install

When dealing with smaller `file.json ~ 14KB` payloads, `JSON v1` handles the processing consistently performant, with
a much smaller deviation, and absolutely no real-world absolute performance differences with `Jason`.

However, with often unusually large `file.json > 5MB` payloads, and if the processing speed for those payloads is
paramount to you (ie, processing them in a real-time manner vs using them in migration scripts or whatever), `JSON v1`
currently significantly slower when compared to `Jason`.
[![Build Status](https://travis-ci.org/cblage/elixir-json.svg?branch=master)](https://travis-ci.org/cblage/elixir-json) [![Hex.pm](https://img.shields.io/hexpm/dt/json.svg?style=flat-square)](https://hex.pm/packages/json) [![Coverage Status](https://coveralls.io/repos/github/cblage/elixir-json/badge.svg?branch=master)](https://coveralls.io/github/cblage/elixir-json?branch=master) [![Inline docs](http://inch-ci.org/github/cblage/elixir-json.svg)](http://inch-ci.org/github/cblage/elixir-json)

#### Small payload `bench/data/utf-8-unescaped.json < 30KB` benchmark results for `JSON v1` and `Jason`

As you can see below, both libraries handle "regular" small `json` payloads beautifully.

`JSON.decode` calls while usually being a bit slower than their `Jason` counterparts, they are more consistently
performant, with a much smaller deviation.

So I would actually advise using `JSON.decode` and `JSON.encode` for smaller payloads.

For `JSON.encode` vs `Jason.encode`, the difference is so minimal, it's not worth arguing about.

| Library | Average | Deviation | median | minimum | maximum |
|---------------- |---------- |----------- |---------- |---------- |----------- |
| `JSON.decode` | 13.35 ms | ±45.95% | 11.47 ms | 8.17 ms | 99.49 ms |
| `Jason.decode` | 0.26 ms | ±246.84% | 0.170 ms | 0.150 ms | 64.35 ms |
| `JSON.encode` | 1.32 ms | ±225.81% | 0.58 ms | 0.28 ms | 103.70 ms |
| `Jason.encode` | 0.30 ms | ±316.71% | 0.163 ms | 0.147 ms | 82.68 ms |

#### Full `benchee` reports for `bench/data/utf-8-unescaped.json < 30KB`:
- `decode`: https://bit.ly/2GVV8dy
- `encode`: https://bit.ly/2v5W0H0


#### Large payload `bench/data/issue-90.json ~ 8MB` benchmark results for `JSON v1` and `Jason`

However, with often unusually large `file.json > 5MB` payloads, and if the processing speed for those payloads is paramount to you
(ie, processing them in a real-time manner vs using them in migration scripts or whatever), then
`JSON v1` would not be the best choice when compared to `Jason`.

| Library | Average | Deviation | median | minimum | maximum |
|---------------- |---------- |----------- |---------- |---------- |----------- |
| `JSON.decode` | 8.93 s | ±5.71% | 8.96 s | 8.10 s | 9.57 s |
| `Jason.decode` | 0.182 s | ±21.60% | 0.171 s | 0.139 s | 0.42 s |
| `JSON.encode` | 5.51 s | ±18.10% | 5.24 s | 4.32 s | 7.36 s |
| `Jason.encode` | 0.186 s | ±26.41% | 0.173 s | 0.122 s | 0.38 s |

### Full `benchee` reports for `bench/data/issue-90.json ~ 8MB`:
- `decode`: https://bit.ly/2HxReEP
- `encode`: https://bit.ly/2HuR0OM

# Plan of action for `Elixir JSON v2`

I am currently working on a solution for this problem in `JSON v2`.
You can follow the process here: https://github.com/cblage/elixir-json/pull/52

# Interim Solution

To processes these large payloads adding the `Jason` lib to your dependencies (without hopefully removing `JSON`
for the smaller payloads :sweat_smile:):
- `Jason@Hex.pm`: http://hex.pm/packages/jason
- `Jason@GitHub`: https://github.com/michalmuskala/jason

After installing `Jason`, you then use `JSON.decode` and `JSON.encode` for small your small `30KB range json` payloads due to the reasons mentioned above.

While `Elixir JSON v2` is not ready to processs the bigger `>5MB json` payloads in time-sensitive operations, you go for `Jason.decode` and `Jason.encode`.

Thanks for the comprehension,
Carlos Brito Lage

## Example
This library provides a natively implemented JSON encoder and decoder for Elixir.

```elixir
[
{:cowboy, "~> 1.0.0"},
{:plug, "~> 1.0"},
{:json, "~> 1.3"},
{:jason, "~> 1.0"},
]
```
You can find the package in [hex.pm](https://hex.pm/packages/json) and the documentation in [hexdocs.pm](https://hexdocs.pm/json/readme.html).

You can find its documentation here: https://hexdocs.pm/jason/readme.html
All contributions are welcome!

# Installing

Simply add ```{:json, "~> 1.3"}``` to your project's ```mix.exs``` file, in the dependencies list and run ```mix deps.get json```.

## Example for a project that already uses [Plug](https://github.com/elixir-plug/plug):

```elixir
[
{:cowboy, "~> 1.0.0"},
{:plug, "~> 1.0"},
{:json, "~> 1.3"},
]
```
Simply add `{:json, "~> 1.4"}` to your project's `mix.exs` and run `mix deps.get`.

# Usage

Encoding an Elixir type

```elixir
@doc "
JSON encode an Elixir list
"
"
list = [key: "this will be a value"]
is_list(list)
# true
Expand All @@ -202,6 +32,7 @@ Encoding an Elixir type
```

Decoding a list from a string that contains JSON

```elixir
@doc "
JSON decode a string into an Elixir list
Expand All @@ -215,7 +46,7 @@ Decoding a list from a string that contains JSON
# "this will be a value"
```

At any time, you can turn on verbose logging for this library only.
At any time, you can turn on verbose logging for this library only.
To do so, head to config file of your application and add below lines:

```elixir
Expand All @@ -229,5 +60,5 @@ config :json, log_level: :debug
Note that, changing only `:logger` level to `:info`, `:warn` or `:error` will silent `:json` too.

# License
The Elixir JSON library is available under the [BSD 3-Clause aka "BSD New" license](http://www.tldrlegal.com/l/BSD3)

The Elixir JSON library is available under the [BSD 3-Clause aka "BSD New" license](http://www.tldrlegal.com/l/BSD3)
9 changes: 3 additions & 6 deletions config/.credo.exs
Expand Up @@ -7,13 +7,10 @@
excluded: []
},
checks: [
{Credo.Check.Warning.LazyLogging, ignore: [:debug]},
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, false},
{Credo.Check.Consistency.TabsOrSpaces},

# For some checks, like AliasUsage, you can only customize the priority
# Priority values are: `low, normal, high, higher`
{Credo.Check.Design.AliasUsage, priority: :low},

{Credo.Check.Refactor.Nesting, max_nesting: 3},
{Credo.Check.Design.AliasUsage, false},
# For others you can also set parameters
{Credo.Check.Readability.MaxLineLength, priority: :low, max_length: 120},

Expand Down
4 changes: 3 additions & 1 deletion config/config.exs
Expand Up @@ -4,6 +4,8 @@ use Mix.Config

config :logger,
level: :info,
compile_time_purge_level: :debug
compile_time_purge_matching: [
[level_lower_than: :info]
]

config :json, log_level: :info
47 changes: 8 additions & 39 deletions lib/json.ex
Expand Up @@ -4,12 +4,13 @@ defmodule JSON do
"""

require Logger

import JSON.Logger

alias JSON.Encoder, as: Encoder
alias JSON.Decoder, as: Decoder
alias JSON.Decoder
alias JSON.Encoder

@vsn "1.0.2"
@vsn "3.0.0-SNAPSHOT"

@doc """
Returns a JSON string representation of the Elixir term
Expand All @@ -21,7 +22,7 @@ defmodule JSON do
"""
@spec encode(term) :: {atom, bitstring}
def encode(term), do: Encoder.encode(term)
defdelegate encode(term), to: Encoder

@doc """
Returns a JSON string representation of the Elixir term, raises errors when something bad happens
Expand All @@ -34,7 +35,7 @@ defmodule JSON do
"""
@spec encode!(term) :: bitstring
def encode!(term) do
case Encoder.encode(term) do
case encode(term) do
{:ok, value} -> value
{:error, error_info} -> raise JSON.Encoder.Error, error_info: error_info
_ -> raise JSON.Encoder.Error
Expand All @@ -51,39 +52,7 @@ defmodule JSON do
"""
@spec decode(bitstring) :: {atom, term}
@spec decode(charlist) :: {atom, term}
def decode(bitstring_or_char_list) do
bitstring_or_char_list
|> Decoder.decode()
|> case do
res = {:ok, _} ->
log(:debug, fn ->
"#{__MODULE__}.decode(#{inspect(bitstring_or_char_list)}} was sucesfull: #{inspect(res)}"
end)

res

e = {:error, {:unexpected_token, tok}} ->
log(:debug, fn ->
"#{__MODULE__}.decode!(#{inspect(bitstring_or_char_list)}} unexpected token #{tok}"
end)

e

e = {:error, :unexpected_end_of_buffer} ->
log(:debug, fn ->
"#{__MODULE__}.decode!(#{inspect(bitstring_or_char_list)}} end of buffer"
end)

e

e ->
log(:debug, fn ->
"#{__MODULE__}.decode!(#{inspect(bitstring_or_char_list)}} an unknown problem occurred #{
inspect(e)
}"
end)
end
end
defdelegate decode(bitstring_or_char_list), to: Decoder

@doc """
Converts a valid JSON string into an Elixir term, raises errors when something bad happens
Expand All @@ -96,7 +65,7 @@ defmodule JSON do
@spec decode!(bitstring) :: term
@spec decode!(charlist) :: term
def decode!(bitstring_or_char_list) do
case Decoder.decode(bitstring_or_char_list) do
case decode(bitstring_or_char_list) do
{:ok, value} ->
log(:debug, fn ->
"#{__MODULE__}.decode!(#{inspect(bitstring_or_char_list)}} was sucesfull: #{
Expand Down

0 comments on commit b3fd56e

Please sign in to comment.