panko_serializer 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/docs.yml +4 -4
- data/.github/workflows/lint.yml +8 -14
- data/.github/workflows/ruby.yml +11 -7
- data/.gitignore +2 -0
- data/.rubocop.yml +29 -21
- data/Appraisals +20 -8
- data/Gemfile +11 -3
- data/README.md +3 -3
- data/Rakefile +3 -1
- data/benchmarks/allocs.rb +2 -2
- data/benchmarks/benchmarking_support.rb +2 -1
- data/benchmarks/bm_ams_0_10.rb +3 -7
- data/benchmarks/bm_panko_json.rb +2 -6
- data/benchmarks/bm_panko_object.rb +2 -6
- data/benchmarks/bm_plain_object.rb +1 -4
- data/benchmarks/bm_serialization_descriptor.rb +1 -1
- data/benchmarks/bm_to_object.rb +2 -6
- data/benchmarks/profile.rb +2 -2
- data/benchmarks/sanity.rb +2 -6
- data/benchmarks/setup.rb +4 -3
- data/benchmarks/type_casts/support.rb +0 -1
- data/docs/docs/associations.md +19 -6
- data/docs/docs/attributes.md +29 -23
- data/docs/docs/design-choices.md +28 -27
- data/docs/docs/getting-started.md +9 -3
- data/docs/docs/introduction.md +5 -5
- data/docs/docs/performance.md +0 -1
- data/docs/docs/response-bag.md +8 -1
- data/docs/docusaurus.config.js +86 -0
- data/docs/package-lock.json +12607 -18674
- data/docs/package.json +14 -7
- data/docs/src/css/customTheme.css +9 -0
- data/docs/static/CNAME +1 -0
- data/ext/panko_serializer/attributes_writer/active_record.c +103 -72
- data/ext/panko_serializer/attributes_writer/active_record.h +2 -0
- data/gemfiles/7.0.0.gemfile +12 -3
- data/gemfiles/7.0.0.gemfile.lock +62 -50
- data/gemfiles/7.1.0.gemfile +15 -6
- data/gemfiles/7.1.0.gemfile.lock +76 -59
- data/gemfiles/{6.1.0.gemfile → 7.2.0.gemfile} +15 -6
- data/gemfiles/{6.1.0.gemfile.lock → 7.2.0.gemfile.lock} +97 -65
- data/gemfiles/8.0.0.gemfile +39 -0
- data/gemfiles/8.0.0.gemfile.lock +219 -0
- data/lib/panko/version.rb +1 -1
- data/panko_serializer.gemspec +1 -1
- metadata +12 -12
- data/.standard.yml +0 -5
- data/docs/.DS_Store +0 -0
- data/docs/README.md +0 -198
- data/docs/core/Footer.js +0 -80
- data/docs/i18n/en.json +0 -50
- data/docs/siteConfig.js +0 -80
data/docs/docs/attributes.md
CHANGED
@@ -3,15 +3,14 @@ id: attributes
|
|
3
3
|
title: Attributes
|
4
4
|
sidebar_label: Attributes
|
5
5
|
---
|
6
|
-
|
7
6
|
Attributes allow you to specify which record attributes you want to serialize,
|
8
7
|
There are two types of attributes:
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
- Field - simple columns defined on the record it self.
|
10
|
+
- Virtual/Method - this allows to include properties beyond simple fields.
|
13
11
|
|
14
12
|
```ruby
|
13
|
+
|
15
14
|
class UserSerializer < Panko::Serializer
|
16
15
|
attributes :full_name
|
17
16
|
|
@@ -19,6 +18,7 @@ class UserSerializer < Panko::Serializer
|
|
19
18
|
"#{object.first_name} #{object.last_name}"
|
20
19
|
end
|
21
20
|
end
|
21
|
+
|
22
22
|
```
|
23
23
|
|
24
24
|
## Field Attributes
|
@@ -27,7 +27,6 @@ Using field attributes you can control which columns of the given ActiveRecord o
|
|
27
27
|
|
28
28
|
Instead of relying ActiveRecord to do it's type casting, Panko does on it's own for performance reasons (read more in [Design Choices](design-choices.md#type-casting)).
|
29
29
|
|
30
|
-
|
31
30
|
## Method Attributes
|
32
31
|
|
33
32
|
Method attributes are used when your serialized values can be derived from the object you are serializing.
|
@@ -35,6 +34,7 @@ Method attributes are used when your serialized values can be derived from the o
|
|
35
34
|
The serializer's attribute methods can access the object being serialized as `object` -
|
36
35
|
|
37
36
|
```ruby
|
37
|
+
|
38
38
|
class PostSerializer < Panko::Serializer
|
39
39
|
attributes :author_name
|
40
40
|
|
@@ -42,12 +42,15 @@ class PostSerializer < Panko::Serializer
|
|
42
42
|
"#{object.author.first_name} #{object.author.last_name}"
|
43
43
|
end
|
44
44
|
end
|
45
|
+
|
45
46
|
```
|
46
47
|
|
47
48
|
Another useful, thing you can pass your serializer is `context`, a `context` is a bag of data whom your serializer may need.
|
48
49
|
|
49
50
|
For example, here we will pass feature flags:
|
51
|
+
|
50
52
|
```ruby
|
53
|
+
|
51
54
|
class UserSerializer < Panko::Serializer
|
52
55
|
attributes :id, :email
|
53
56
|
|
@@ -61,6 +64,7 @@ serializer = UserSerializer.new(context: {
|
|
61
64
|
})
|
62
65
|
|
63
66
|
serializer.serialize(User.first)
|
67
|
+
|
64
68
|
```
|
65
69
|
|
66
70
|
## Filters
|
@@ -68,11 +72,14 @@ serializer.serialize(User.first)
|
|
68
72
|
Filters allows us to reduce the amount of attributes we can serialize, therefore reduce the data usage & performance of serializing.
|
69
73
|
|
70
74
|
There are two types of filters:
|
71
|
-
|
72
|
-
|
75
|
+
|
76
|
+
- only - use those attributes **only** and nothing else
|
77
|
+
- except - all attributes **except** those attributes
|
73
78
|
|
74
79
|
Usage example:
|
80
|
+
|
75
81
|
```ruby
|
82
|
+
|
76
83
|
class UserSerializer < Panko::Serializer
|
77
84
|
attributes :id, :name, :email
|
78
85
|
end
|
@@ -82,13 +89,14 @@ UserSerializer.new(only: [:name]).serialize(User.first)
|
|
82
89
|
|
83
90
|
# this line will return { 'id': '..', 'email': ... }
|
84
91
|
UserSerializer.new(except: [:name]).serialize(User.first)
|
92
|
+
|
85
93
|
```
|
86
94
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
95
|
+
> **Note** that if you want to user filter on an associations, the `:name`
|
96
|
+
> property is not taken into account.
|
97
|
+
> If you have a `has_many :state_transitions, name: :history` association
|
98
|
+
> defined, the key to use in filters is `:state_transitions`
|
99
|
+
> (e.g. `{ except: [:state_transitions] }`)
|
92
100
|
|
93
101
|
## Filters For
|
94
102
|
|
@@ -96,6 +104,7 @@ Sometimes you find yourself have the same filtering logic in actions in order to
|
|
96
104
|
solve this duplication, Panko allows you to write the filters in the serializer.
|
97
105
|
|
98
106
|
```ruby
|
107
|
+
|
99
108
|
class UserSerializer < Panko::Serializer
|
100
109
|
attributes :id, :name, :email
|
101
110
|
|
@@ -108,30 +117,27 @@ end
|
|
108
117
|
|
109
118
|
# this line will return { 'name': '..' }
|
110
119
|
UserSerializer.serialize(User.first)
|
120
|
+
|
111
121
|
```
|
112
122
|
|
113
|
-
|
123
|
+
> See discussion in: https:
|
114
124
|
|
115
125
|
## Aliases
|
116
126
|
|
117
127
|
Let's say we have attribute name that we want to expose to client as different name, the current way of doing so is using method attribute, for example:
|
118
128
|
|
119
129
|
```ruby
|
120
|
-
class PostSerializer < Panko::Serializer
|
121
|
-
attributes :published_at
|
122
130
|
|
123
|
-
|
124
|
-
|
125
|
-
end
|
126
|
-
end
|
131
|
+
|
132
|
+
|
127
133
|
```
|
128
134
|
|
129
|
-
The downside of this approach is that
|
135
|
+
The downside of this approach is that `` skips Panko's type casting, therefore we get direct hit on performance.
|
130
136
|
|
131
137
|
To fix this, we can use aliases -
|
132
138
|
|
133
139
|
```ruby
|
134
|
-
|
135
|
-
|
136
|
-
|
140
|
+
|
141
|
+
|
142
|
+
|
137
143
|
```
|
data/docs/docs/design-choices.md
CHANGED
@@ -3,15 +3,13 @@ id: design-choices
|
|
3
3
|
title: Design Choices
|
4
4
|
sidebar_label: Design Choices
|
5
5
|
---
|
6
|
-
|
7
6
|
In short, Panko, is a serializer for ActiveRecord objects (it can't serialize any other object), which strives for high performance & simple API (which is inspired by ActiveModelSerializers).
|
8
7
|
|
9
8
|
Its performance is achieved by:
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
- `Oj::StringWriter` - I will elaborate later.
|
11
|
+
- Type casting — instead of relying on ActiveRecord to do its type cast, Panko is doing it by itself.
|
12
|
+
- Figuring out the metadata, ahead of time — therefore, we ask less questions during the `serialization loop`.
|
15
13
|
|
16
14
|
## Serialization overview
|
17
15
|
|
@@ -21,6 +19,7 @@ First, let's start with overview. Let's say we want to serialize `User` object,
|
|
21
19
|
The serializer definition will be something like this:
|
22
20
|
|
23
21
|
```ruby
|
22
|
+
|
24
23
|
class UserSerializer < Panko::Serializer
|
25
24
|
attributes :name, :age, :email
|
26
25
|
|
@@ -28,11 +27,13 @@ class UserSerializer < Panko::Serializer
|
|
28
27
|
"#{object.first_name} #{object.last_name}"
|
29
28
|
end
|
30
29
|
end
|
30
|
+
|
31
31
|
```
|
32
32
|
|
33
33
|
And the usage of this serializer will be:
|
34
34
|
|
35
35
|
```ruby
|
36
|
+
|
36
37
|
# fetch user from database
|
37
38
|
user = User.first
|
38
39
|
|
@@ -41,6 +42,7 @@ serializer = UserSerializer.new
|
|
41
42
|
|
42
43
|
# serialize to JSON
|
43
44
|
serializer.serialize_to_json(user)
|
45
|
+
|
44
46
|
```
|
45
47
|
|
46
48
|
Let's go over the steps that Panko will execute behind the scenes for this flow.
|
@@ -49,19 +51,19 @@ _I will skip the serializer definition part, because it's fairly simple and stra
|
|
49
51
|
First step, while initializing the UserSerializer, we will create a **Serialization Descriptor** for this class.
|
50
52
|
Serialization Descriptor's goal is to answer those questions:
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
- Which fields do we have? In our case, `:age`, `:email`
|
55
|
+
- Which method fields do we have? In our case `:name`
|
56
|
+
- Which associations do we have (and their serialization descriptors)
|
55
57
|
|
56
|
-
The serialization description is also responsible for filtering the attributes (`only`
|
58
|
+
The serialization description is also responsible for filtering the attributes (`only` \\ `except`).
|
57
59
|
|
58
|
-
Now, that we have the serialization descriptor, we are finished with the Ruby part of Panko, and all we did here is done in
|
60
|
+
Now, that we have the serialization descriptor, we are finished with the Ruby part of Panko, and all we did here is done in _initialization time_ and now we move to C code.
|
59
61
|
|
60
62
|
In C land, we take the `user` object and the serialization descriptor, and start the serialization process which is separated to 4 parts:
|
61
63
|
|
62
|
-
|
63
|
-
|
64
|
-
|
64
|
+
- Serializing Fields - looping through serialization descriptor's `fields` and read them from the ActiveRecord object (see `Type Casting`) and write them to the writer.
|
65
|
+
- Serializing Method Fields - creating (a cached) serializer instance, setting its `@object` and `@context`, calling all the method fields and writing them to the writer.
|
66
|
+
- Serializing associations — this is simple, once we have fields + method fields, we just repeat the process.
|
65
67
|
|
66
68
|
Once this is finished, we have nice JSON string.
|
67
69
|
Now let's dig deeper.
|
@@ -72,31 +74,30 @@ Now let's dig deeper.
|
|
72
74
|
|
73
75
|
If you read the code of ActiveRecord serialization code in Ruby, you will observe this flow:
|
74
76
|
|
75
|
-
1.
|
76
|
-
2.
|
77
|
-
3.
|
77
|
+
1. Get an array of ActiveRecord objects (`User.all` for example)
|
78
|
+
2. Build new array of hashes where each hash is `User` with the attributes we selected
|
79
|
+
3. The JSON serializer, takes this array of hashes and loop them, and converts it to JSON string
|
78
80
|
|
79
81
|
This entire process is expensive in terms of Memory & CPU, and this where the combination of Panko and Oj::StringWriter really shines.
|
80
82
|
|
81
83
|
In Panko, the serialization process of the above is:
|
82
84
|
|
83
|
-
1.
|
84
|
-
2.
|
85
|
-
3.
|
85
|
+
1. Get an array of ActiveRecord objects (`User.all` for example)
|
86
|
+
2. Create `Oj::StringWriter` and feed the values to it, via `push_value` / `push_object` / `push_object` and behind the scene, `Oj::StringWriter` will serialize the objects incrementally into a string.
|
87
|
+
3. Get from `Oj::StringWriter` the completed JSON string — which is a no-op, since `Oj::StringWriter` already built the string.
|
86
88
|
|
87
89
|
### Figuring out the metadata, ahead of time.
|
88
90
|
|
89
91
|
Another observation I noticed in the ruby serializers is that they ask and do a lot in a serialization loop:
|
90
92
|
|
91
|
-
|
92
|
-
|
93
|
-
|
93
|
+
- Is this field a method? is it a property?
|
94
|
+
- Which fields and associations do I need for the serializer to consider the `only` and `except` options
|
95
|
+
- What is the serializer of this has_one association?
|
94
96
|
|
95
97
|
Panko tries to ask the bare minimum in serialization by building `Serialization Descriptor` for each serialization and caching it.
|
96
98
|
|
97
99
|
The Serialization Descriptor will do the filtering of `only` and `except` and will check if a field is a method or not (therefore Panko doesn't have list of `attributes`)
|
98
100
|
|
99
|
-
|
100
101
|
### Type Casting
|
101
102
|
|
102
103
|
This is the final part, which helped yield most of the performance improvements.
|
@@ -114,13 +115,13 @@ If we have an integer string value, we will convert it to an integer, and the sa
|
|
114
115
|
All of these conversions are done in C, which of course yields a big performance improvement.
|
115
116
|
|
116
117
|
#### Time type casting
|
118
|
+
|
117
119
|
While you read Panko source code, you will encounter the time type casting and immediately you will have a "WTF?" moment.
|
118
120
|
|
119
121
|
The idea behind the time type casting code relies on the end result of JSON type casting — what we need in order to serialize Time to JSON? UTC ISO8601 time format representation.
|
120
122
|
|
121
123
|
The time type casting works as follows:
|
122
124
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
125
|
+
- If it's a string that ends with `Z`, and the strings matches the UTC ISO8601 regex, then we just return the string.
|
126
|
+
- If it's a string and it doesn't follow the rules above, we check if it's a timestamp in database format and convert it via regex + string concat to UTC ISO8601 - Yes, there is huge assumption here, that the database returns UTC timestamps — this will be configureable (before Panko official release).
|
127
|
+
- If it's none of the above, I will let ActiveRecord type casting do it's magic.
|
@@ -3,21 +3,23 @@ id: getting-started
|
|
3
3
|
title: Getting Started
|
4
4
|
sidebar_label: Getting Started
|
5
5
|
---
|
6
|
-
|
7
6
|
## Installation
|
8
7
|
|
9
8
|
To install Panko, all you need is to add it to your Gemfile:
|
10
9
|
|
11
10
|
```ruby
|
11
|
+
|
12
12
|
gem "panko_serializer"
|
13
|
+
|
13
14
|
```
|
14
15
|
|
15
16
|
Then, install it on the command line:
|
16
17
|
|
17
18
|
```
|
18
|
-
> bundle install
|
19
|
-
```
|
20
19
|
|
20
|
+
bundle install
|
21
|
+
|
22
|
+
```
|
21
23
|
|
22
24
|
## Creating your first serializer
|
23
25
|
|
@@ -40,11 +42,13 @@ end
|
|
40
42
|
And now serialize a single object
|
41
43
|
|
42
44
|
```ruby
|
45
|
+
|
43
46
|
# Using Oj serializer
|
44
47
|
PostSerializer.new.serialize_to_json(Post.first)
|
45
48
|
|
46
49
|
# or, similar to #serializable_hash
|
47
50
|
PostSerializer.new.serialize(Post.first).to_json
|
51
|
+
|
48
52
|
```
|
49
53
|
|
50
54
|
### Using the serializers in a controller
|
@@ -53,12 +57,14 @@ As you can see, defining serializers is simple and resembles ActiveModelSerializ
|
|
53
57
|
To utilize the `UserSerializer` inside a Rails controller and serialize some users, all we need to do is:
|
54
58
|
|
55
59
|
```ruby
|
60
|
+
|
56
61
|
class UsersController < ApplicationController
|
57
62
|
def index
|
58
63
|
users = User.includes(:posts).all
|
59
64
|
render json: Panko::ArraySerializer.new(users, each_serializer: UserSerializer).to_json
|
60
65
|
end
|
61
66
|
end
|
67
|
+
|
62
68
|
```
|
63
69
|
|
64
70
|
And voila, we have endpoint which serialize users using Panko!
|
data/docs/docs/introduction.md
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
id: index
|
3
3
|
title: Introduction
|
4
4
|
sidebar_label: Introduction
|
5
|
+
slug: /
|
5
6
|
---
|
6
|
-
|
7
7
|
Panko is library which is inspired by ActiveModelSerializers 0.9 for serializing ActiveRecord/Ruby objects to JSON strings, fast.
|
8
8
|
|
9
|
-
To achieve it's [performance](https://panko.dev/docs/performance
|
9
|
+
To achieve it's [performance](https://panko.dev/docs/performance/):
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
- Oj - Panko relies Oj since it's fast and allow to serialize incrementally using `Oj::StringWriter`
|
12
|
+
- Serialization Descriptor - Panko computes most of the metadata ahead of time, to save time later in serialization.
|
13
|
+
- Type casting — Panko does type casting by it's self, instead of relying ActiveRecord.
|
data/docs/docs/performance.md
CHANGED
data/docs/docs/response-bag.md
CHANGED
@@ -3,11 +3,11 @@ id: response-bag
|
|
3
3
|
title: Response
|
4
4
|
sidebar_label: Response
|
5
5
|
---
|
6
|
-
|
7
6
|
Let's say you have some JSON payload which can is constructed using Panko serialization result,
|
8
7
|
like this:
|
9
8
|
|
10
9
|
```ruby
|
10
|
+
|
11
11
|
class PostsController < ApplicationController
|
12
12
|
def index
|
13
13
|
posts = Post.all
|
@@ -18,11 +18,13 @@ class PostsController < ApplicationController
|
|
18
18
|
}
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
21
22
|
```
|
22
23
|
|
23
24
|
The output of the above will be json string (for `posts`) inside json string and this were `Panko::Response` shines.
|
24
25
|
|
25
26
|
```ruby
|
27
|
+
|
26
28
|
class PostsController < ApplicationController
|
27
29
|
def index
|
28
30
|
posts = Post.all
|
@@ -33,6 +35,7 @@ class PostsController < ApplicationController
|
|
33
35
|
)
|
34
36
|
end
|
35
37
|
end
|
38
|
+
|
36
39
|
```
|
37
40
|
|
38
41
|
And everything will work as expected!
|
@@ -40,6 +43,7 @@ And everything will work as expected!
|
|
40
43
|
For a single object serialization, we need to use a different API (since `Panko::Serializer` don't accept an object in it's constructor):
|
41
44
|
|
42
45
|
```ruby
|
46
|
+
|
43
47
|
class PostsController < ApplicationController
|
44
48
|
def show
|
45
49
|
post = Post.find(params[:id])
|
@@ -54,6 +58,7 @@ class PostsController < ApplicationController
|
|
54
58
|
)
|
55
59
|
end
|
56
60
|
end
|
61
|
+
|
57
62
|
```
|
58
63
|
|
59
64
|
## JsonValue
|
@@ -62,6 +67,7 @@ Let's take the above example further, we serialized the posts and cached it as J
|
|
62
67
|
Now, you can wrap the cached value with `Panko::JsonValue`, like here -
|
63
68
|
|
64
69
|
```ruby
|
70
|
+
|
65
71
|
class PostsController < ApplicationController
|
66
72
|
def index
|
67
73
|
posts = Cache.get("/posts")
|
@@ -73,4 +79,5 @@ class PostsController < ApplicationController
|
|
73
79
|
)
|
74
80
|
end
|
75
81
|
end
|
82
|
+
|
76
83
|
```
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module.exports = {
|
2
|
+
"title": "Panko Serializers",
|
3
|
+
"tagline": "High Performance JSON Serialization for ActiveRecord & Ruby Objects",
|
4
|
+
"url": "https://panko.dev",
|
5
|
+
"baseUrl": "/",
|
6
|
+
"organizationName": "yosiat",
|
7
|
+
"projectName": "panko_serializer",
|
8
|
+
"favicon": "favicon.ico",
|
9
|
+
"customFields": {
|
10
|
+
"repoPath": "yosiat/panko_serializer",
|
11
|
+
"repoUrl": "https://github.com/yosiat/panko_serializer",
|
12
|
+
},
|
13
|
+
"onBrokenLinks": "log",
|
14
|
+
"onBrokenMarkdownLinks": "log",
|
15
|
+
"presets": [
|
16
|
+
[
|
17
|
+
"@docusaurus/preset-classic",
|
18
|
+
{
|
19
|
+
"docs": {
|
20
|
+
"path": "./docs",
|
21
|
+
"showLastUpdateAuthor": false,
|
22
|
+
"showLastUpdateTime": false,
|
23
|
+
"sidebarPath": "./sidebars.json",
|
24
|
+
"routeBasePath": process.env.NODE_ENV === 'production' ? '/docs' : '/',
|
25
|
+
},
|
26
|
+
"blog": false,
|
27
|
+
"pages": false,
|
28
|
+
"theme": {
|
29
|
+
"customCss": "./src/css/customTheme.css"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
]
|
33
|
+
],
|
34
|
+
"plugins": [],
|
35
|
+
"themeConfig": {
|
36
|
+
colorMode: {
|
37
|
+
defaultMode: 'light',
|
38
|
+
disableSwitch: true,
|
39
|
+
},
|
40
|
+
"navbar": {
|
41
|
+
"title": "Panko Serializers",
|
42
|
+
"items": [
|
43
|
+
{
|
44
|
+
"to": "introduction",
|
45
|
+
"label": "Docs",
|
46
|
+
"position": "left"
|
47
|
+
}
|
48
|
+
]
|
49
|
+
},
|
50
|
+
"image": "img/undraw_online.svg",
|
51
|
+
"footer": {
|
52
|
+
"links": [
|
53
|
+
{
|
54
|
+
title: "GitHub",
|
55
|
+
items: [
|
56
|
+
{
|
57
|
+
label: "Repository",
|
58
|
+
href: "https://github.com/yosiat/panko_serializer"
|
59
|
+
},
|
60
|
+
{
|
61
|
+
label: "Discussions",
|
62
|
+
href: "https://github.com/yosiat/panko_serializer/discussions"
|
63
|
+
},
|
64
|
+
{
|
65
|
+
label: "Issues",
|
66
|
+
href: "https://github.com/yosiat/panko_serializer/issues"
|
67
|
+
},
|
68
|
+
{
|
69
|
+
"html": `
|
70
|
+
<iframe
|
71
|
+
src="https://ghbtns.com/github-btn.html?user=yosiat&repo=panko_serializer&type=star&count=true&size=medium"
|
72
|
+
title="GitHub Stars"
|
73
|
+
/>`
|
74
|
+
}
|
75
|
+
]
|
76
|
+
}
|
77
|
+
],
|
78
|
+
"copyright": `Copyright © ${new Date().getFullYear()} Panko Serializer`,
|
79
|
+
},
|
80
|
+
prism: {
|
81
|
+
theme: require('prism-react-renderer/themes/github'), // Optional: Customize theme
|
82
|
+
darkTheme: require('prism-react-renderer/themes/dracula'), // Optional: Dark theme
|
83
|
+
additionalLanguages: ['ruby'], // Add Ruby as an additional language
|
84
|
+
},
|
85
|
+
}
|
86
|
+
}
|