stylegen 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5882aa3fdd2e17f9e0fe683c07fd07d5c045f505a78a8ba7c5765edfc60a2c6e
4
+ data.tar.gz: f583e4f26b3e4dccc121eceec5a7f5e4349f7210e660527aa07128f1401e2837
5
+ SHA512:
6
+ metadata.gz: d525975a51b7415c727b1f46299ec37283bcc2d2efbde3450cc361c4095c27abc7d2d606863676acc8f35950dbe885519cf1568fab89520fb731cf92812445d0
7
+ data.tar.gz: 6aa2ac484c0697175a7f6e1ebf94221fcbf66f78e2ba11d3e351434c1949646bc3ff49e46ccf9895703327217a33e1c766d5eb9c3df1f9589b92f210ded81395
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ ruby-version:
16
+ - "2.5"
17
+ - "2.6"
18
+ - "2.7"
19
+ - "3.0"
20
+
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ - name: Set up Ruby
24
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
25
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
26
+ # uses: ruby/setup-ruby@v1
27
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: Run tests
32
+ run: bundle exec rake
@@ -0,0 +1,2 @@
1
+ .idea
2
+ pkg
@@ -0,0 +1,33 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-minitest
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 2.4
7
+ NewCops: enable
8
+
9
+ Style/StringLiterals:
10
+ Enabled: true
11
+ EnforcedStyle: double_quotes
12
+
13
+ Metrics/ClassLength:
14
+ Enabled: true
15
+ Max: 150
16
+
17
+ Naming/MethodParameterName:
18
+ Enabled: false
19
+
20
+ Metrics/MethodLength:
21
+ Enabled: false
22
+
23
+ Metrics/AbcSize:
24
+ Enabled: false
25
+
26
+ Style/Documentation:
27
+ Enabled: false
28
+
29
+ Style/ParallelAssignment:
30
+ Enabled: false
31
+
32
+ Minitest/AssertInDelta:
33
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
@@ -0,0 +1,61 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ stylegen (0.1.0)
5
+ dry-inflector (>= 0.2.0)
6
+ json_schemer (>= 0.2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.1)
12
+ dry-inflector (0.2.0)
13
+ ecma-re-validator (0.3.0)
14
+ regexp_parser (~> 2.0)
15
+ hana (1.3.7)
16
+ json_schemer (0.2.17)
17
+ ecma-re-validator (~> 0.3)
18
+ hana (~> 1.3)
19
+ regexp_parser (~> 2.0)
20
+ uri_template (~> 0.7)
21
+ minitest (5.14.3)
22
+ parallel (1.20.1)
23
+ parser (3.0.0.0)
24
+ ast (~> 2.4.1)
25
+ rainbow (3.0.0)
26
+ rake (13.0.3)
27
+ regexp_parser (2.0.3)
28
+ rexml (3.2.4)
29
+ rubocop (1.8.1)
30
+ parallel (~> 1.10)
31
+ parser (>= 3.0.0.0)
32
+ rainbow (>= 2.2.2, < 4.0)
33
+ regexp_parser (>= 1.8, < 3.0)
34
+ rexml
35
+ rubocop-ast (>= 1.2.0, < 2.0)
36
+ ruby-progressbar (~> 1.7)
37
+ unicode-display_width (>= 1.4.0, < 3.0)
38
+ rubocop-ast (1.4.0)
39
+ parser (>= 2.7.1.5)
40
+ rubocop-minitest (0.10.3)
41
+ rubocop (>= 0.87, < 2.0)
42
+ rubocop-rake (0.5.1)
43
+ rubocop
44
+ ruby-progressbar (1.11.0)
45
+ unicode-display_width (2.0.0)
46
+ uri_template (0.7.0)
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ bundler
53
+ minitest (>= 5.14.0)
54
+ rake
55
+ rubocop
56
+ rubocop-minitest
57
+ rubocop-rake
58
+ stylegen!
59
+
60
+ BUNDLED WITH
61
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2021 Ramon Torres
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,97 @@
1
+ # stylegen
2
+
3
+ A CLI utility that allows managing the colors used in an iOS app from a centralized YAML file in a type-safe way.
4
+
5
+ ![CI](https://github.com/raymondjavaxx/stylegen/workflows/CI/badge.svg?branch=master)
6
+
7
+ ## Installing
8
+
9
+ You can install `stylegen` manually by running:
10
+
11
+ ```shell
12
+ $ gem install stylegen
13
+ ```
14
+
15
+ Or by adding the following entry to your [Gemfile](https://guides.cocoapods.org/using/a-gemfile.html), then running `$ bundle install`.
16
+
17
+ ```ruby
18
+ gem "stylegen"
19
+ ```
20
+
21
+ ## How to use
22
+
23
+ Create a `theme.yaml` file in the root of your project. You can use the following YAML file as a starting point:
24
+
25
+ ```yaml
26
+ # Name of the design system. Defaults to "Theme".
27
+ # Feel free to use your company name, name of product,
28
+ # or name of your design system.
29
+ # e.g.: Primer, Material, Polaris, etc.
30
+ system_name: "Theme"
31
+
32
+ # Path of generated Swift file.
33
+ output_path: "Colors.swift"
34
+
35
+ # Key-value pairs of theme colors.
36
+ colors:
37
+
38
+ accent: # Keys will be used as color names.
39
+ color: "#00BFC2" # Hex color
40
+
41
+ # Shorthand syntax
42
+ warning: "#ED4337"
43
+
44
+ text_primary:
45
+ light: # Value for light mode
46
+ color: "#000000"
47
+ # Optionally you can specify an alpha value.
48
+ # Defaults to `1.0`.
49
+ alpha: 0.95
50
+ dark: # Value for dark mode
51
+ color: "#FFFFFF"
52
+
53
+ text_secondary:
54
+ light:
55
+ color: "#000000"
56
+ alpha: 0.4
57
+ dark:
58
+ color: "#FFFFFF"
59
+ alpha: 0.6
60
+
61
+ primary_background:
62
+ light: "#FFFFFF"
63
+ dark:
64
+ # Value for base (non-elevated) level
65
+ base: "#0D0D0D"
66
+ # Value for elevated level
67
+ elevated: "#191D1D"
68
+ ```
69
+
70
+ After creating the theme file run:
71
+
72
+ ```shell
73
+ $ stylegen
74
+ ```
75
+
76
+ This will generate a Swift file that you can add to your target. The generated file will contain all the colors and utility methods for referencing the colors.
77
+
78
+ In places where you normally do:
79
+
80
+ ```swift
81
+ self.backgroundColor = UIColor(named: "AccentColor")
82
+ ```
83
+
84
+ Now you can just do:
85
+
86
+ ```swift
87
+ self.backgroundColor = .theme(.accent)
88
+ ```
89
+
90
+ The `.theme()` static method serves as a namespace to easily distinguish between UIKit's built-in colors and our custom colors. The name of the namespacing function is inferred from the `system_name` property in the YAML file.
91
+
92
+ ## TODO
93
+
94
+ * `$ stylegen init` command
95
+ * Option to specify target frameworks: AppKit, UIKit, Core Graphics, and SwiftUI
96
+ * SwiftUI support
97
+ * AppKit support
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new
7
+
8
+ task default: :test
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "yaml"
5
+ require "optparse"
6
+ require "stylegen"
7
+
8
+ @options = {}
9
+
10
+ OptionParser.new do |opts|
11
+ opts.on_tail("--version", "Show version") do
12
+ puts Stylegen::VERSION
13
+ exit
14
+ end
15
+ end.parse!
16
+
17
+ data = File.open("theme.yaml") { |file| YAML.safe_load(file) }
18
+
19
+ validator = Stylegen::Validator.new
20
+ unless validator.valid?(data)
21
+ warn "theme.yaml contains one or more errors:"
22
+
23
+ validator.validate(data).each do |e|
24
+ warn " #{e}"
25
+ end
26
+
27
+ exit(1)
28
+ end
29
+
30
+ generator = Stylegen::Generator.new(data)
31
+ generator.generate
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stylegen/version"
4
+ require "stylegen/colors"
5
+ require "stylegen/generator"
6
+ require "stylegen/data"
7
+ require "stylegen/validator"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stylegen/colors/color"
4
+ require "stylegen/colors/light_dark_color"
5
+ require "stylegen/colors/base_elevated_color"
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ class BaseElevatedColor
5
+ def initialize(base, elevated)
6
+ @base, @elevated = base, elevated
7
+ end
8
+
9
+ def to_s(struct_name, indent = 0)
10
+ indent_prefix = " " * indent
11
+
12
+ result = []
13
+ result << "#{struct_name}("
14
+ result << "#{indent_prefix} base: #{@base.to_s(struct_name, indent + 4)},"
15
+ result << "#{indent_prefix} elevated: #{@elevated.to_s(struct_name, indent + 4)}"
16
+ result << "#{indent_prefix})"
17
+
18
+ result.join("\n")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ class Color
5
+ attr_reader :red, :green, :blue, :alpha
6
+
7
+ def initialize(r, g, b, a)
8
+ @red, @green, @blue, @alpha = r, g, b, a
9
+ end
10
+
11
+ def self.from_hex(hex, alpha = nil)
12
+ if (match = hex.downcase.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/))
13
+ r = Integer(match.captures[0], 16) / 255.0
14
+ g = Integer(match.captures[1], 16) / 255.0
15
+ b = Integer(match.captures[2], 16) / 255.0
16
+ elsif (match = hex.downcase.match(/^#?([a-f\d])([a-f\d])([a-f\d])$/))
17
+ r = Integer(match.captures[0] * 2, 16) / 255.0
18
+ g = Integer(match.captures[1] * 2, 16) / 255.0
19
+ b = Integer(match.captures[2] * 2, 16) / 255.0
20
+ else
21
+ raise ArgumentError, "Invalid color syntax: #{hex}"
22
+ end
23
+
24
+ max_digits = 2
25
+
26
+ Color.new(r.round(max_digits), g.round(max_digits), b.round(max_digits), alpha || 1.0)
27
+ end
28
+
29
+ def grayscale?
30
+ @red == @green && @green == @blue
31
+ end
32
+
33
+ def to_s(struct_name, _indent = 0)
34
+ if grayscale?
35
+ "#{struct_name}(white: #{@red}, alpha: #{@alpha})"
36
+ else
37
+ "#{struct_name}(red: #{@red}, green: #{@green}, blue: #{@blue}, alpha: #{@alpha})"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ class LightDarkColor
5
+ def initialize(light, dark)
6
+ @light, @dark = light, dark
7
+ end
8
+
9
+ def to_s(struct_name, indent = 0)
10
+ indent_prefix = " " * indent
11
+
12
+ result = []
13
+ result << "#{struct_name}("
14
+ result << "#{indent_prefix} light: #{@light.to_s(struct_name, indent + 4)},"
15
+ result << "#{indent_prefix} dark: #{@dark.to_s(struct_name, indent + 4)}"
16
+ result << "#{indent_prefix})"
17
+
18
+ result.join("\n")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/inflector"
4
+ require "stylegen/version"
5
+ require "stylegen/colors"
6
+
7
+ module Stylegen
8
+ class Data
9
+ def initialize(data)
10
+ @data = data
11
+ end
12
+
13
+ def inflector
14
+ @inflector ||= Dry::Inflector.new
15
+ end
16
+
17
+ def version
18
+ Stylegen::VERSION
19
+ end
20
+
21
+ def system_name
22
+ @data["system_name"] || "Theme"
23
+ end
24
+
25
+ def util_method_name
26
+ inflector.camelize_lower(inflector.underscore(system_name))
27
+ end
28
+
29
+ def output_path
30
+ @data["output_path"]
31
+ end
32
+
33
+ def basename
34
+ File.basename(@data["output_path"])
35
+ end
36
+
37
+ def access_level
38
+ @data["access_level"] || "internal"
39
+ end
40
+
41
+ def struct_name
42
+ "#{system_name}Color"
43
+ end
44
+
45
+ def colors
46
+ @data["colors"].each do |key, value|
47
+ yield inflector.camelize_lower(key), generate_color(value)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def generate_color(data)
54
+ if data.is_a?(String)
55
+ Color.from_hex(data)
56
+ elsif data.key?("color")
57
+ Color.from_hex(data["color"], data["alpha"])
58
+ elsif data.key?("light")
59
+ LightDarkColor.new(
60
+ generate_color(data["light"]),
61
+ generate_color(data["dark"])
62
+ )
63
+ elsif data.key?("base")
64
+ BaseElevatedColor.new(
65
+ generate_color(data["base"]),
66
+ generate_color(data["elevated"])
67
+ )
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stylegen/data"
4
+
5
+ module Stylegen
6
+ class Generator
7
+ def initialize(data)
8
+ @data = Data.new(data)
9
+ @file = File.open(@data.output_path, "w")
10
+ end
11
+
12
+ def out(line)
13
+ @file << line << "\n"
14
+ end
15
+
16
+ def generate
17
+ generate_header
18
+ generate_struct
19
+ generate_colors
20
+ generate_extensions
21
+ end
22
+
23
+ private
24
+
25
+ def generate_header
26
+ out "//"
27
+ out "// #{@data.basename}"
28
+ out "//"
29
+ out "// Autogenerated by stylegen (v#{@data.version})"
30
+ out "// DO NOT EDIT"
31
+ out "//"
32
+ out ""
33
+ out "import UIKit"
34
+ out ""
35
+ end
36
+
37
+ def generate_struct
38
+ out "#{@data.access_level} struct #{@data.struct_name} {"
39
+ out ""
40
+ out " let uiColor: UIColor"
41
+ out ""
42
+ out " fileprivate init(white: CGFloat, alpha: CGFloat) {"
43
+ out " self.uiColor = UIColor(white: white, alpha: alpha)"
44
+ out " }"
45
+ out ""
46
+ out " fileprivate init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {"
47
+ out " self.uiColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)"
48
+ out " }"
49
+ out ""
50
+ out " fileprivate init(_ color: UIColor) {"
51
+ out " self.uiColor = color"
52
+ out " }"
53
+ out ""
54
+ out " fileprivate init(light: #{@data.struct_name}, dark: #{@data.struct_name}) {"
55
+ out " if #available(iOS 13.0, *) {"
56
+ out " self.uiColor = UIColor(dynamicProvider: { (traits: UITraitCollection) -> UIColor in"
57
+ out " switch traits.userInterfaceStyle {"
58
+ out " case .dark:"
59
+ out " return dark.uiColor"
60
+ out " default:"
61
+ out " return light.uiColor"
62
+ out " }"
63
+ out " })"
64
+ out " } else {"
65
+ out " self.uiColor = light.uiColor"
66
+ out " }"
67
+ out " }"
68
+ out ""
69
+ out " fileprivate init(base: #{@data.struct_name}, elevated: #{@data.struct_name}) {"
70
+ out " if #available(iOS 13.0, *) {"
71
+ out " self.uiColor = UIColor(dynamicProvider: { (traits: UITraitCollection) -> UIColor in"
72
+ out " switch traits.userInterfaceLevel {"
73
+ out " case .elevated:"
74
+ out " return elevated.uiColor"
75
+ out " default:"
76
+ out " return base.uiColor"
77
+ out " }"
78
+ out " })"
79
+ out " } else {"
80
+ out " self.uiColor = base.uiColor"
81
+ out " }"
82
+ out " }"
83
+ out ""
84
+ out "}"
85
+ out ""
86
+ end
87
+
88
+ def generate_colors
89
+ out "#{@data.access_level} extension #{@data.struct_name} {"
90
+ out ""
91
+
92
+ @data.colors do |member, color|
93
+ out " static let #{member} = #{color.to_s(@data.struct_name, 4)}"
94
+ out ""
95
+ end
96
+
97
+ out "}"
98
+ out ""
99
+ end
100
+
101
+ def generate_extensions
102
+ out "#{@data.access_level} extension UIColor {"
103
+ out ""
104
+ out " @inline(__always)"
105
+ out " static func #{@data.util_method_name}(_ color: #{@data.struct_name}) -> UIColor {"
106
+ out " return color.uiColor"
107
+ out " }"
108
+ out ""
109
+ out "}"
110
+ out ""
111
+
112
+ out "#{@data.access_level} extension CGColor {"
113
+ out ""
114
+ out " @inline(__always)"
115
+ out " static func #{@data.util_method_name}(_ color: #{@data.struct_name}) -> CGColor {"
116
+ out " return color.uiColor.cgColor"
117
+ out " }"
118
+ out ""
119
+ out "}"
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,105 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "stylegen configuration",
4
+ "type": "object",
5
+ "definitions": {
6
+ "AbstractColor": {
7
+ "oneOf": [
8
+ {
9
+ "$ref": "#/definitions/HexColor"
10
+ },
11
+ {
12
+ "$ref": "#/definitions/Color"
13
+ },
14
+ {
15
+ "$ref": "#/definitions/BaseElevatedColor"
16
+ },
17
+ {
18
+ "$ref": "#/definitions/LightDarkColor"
19
+ }
20
+ ]
21
+ },
22
+ "HexColor": {
23
+ "type": "string",
24
+ "pattern": "^#?([0-9a-fA-F]{3})([0-9a-fA-F]{3})?$"
25
+ },
26
+ "Color": {
27
+ "type": "object",
28
+ "properties": {
29
+ "color": {
30
+ "$ref": "#/definitions/HexColor"
31
+ },
32
+ "alpha": {
33
+ "type": "number",
34
+ "minimum": 0.0,
35
+ "maximum": 1.0
36
+ }
37
+ },
38
+ "required": ["color"],
39
+ "additionalProperties": false
40
+ },
41
+ "BaseElevatedColor": {
42
+ "type": "object",
43
+ "properties": {
44
+ "base": {
45
+ "$ref": "#/definitions/AbstractColor"
46
+ },
47
+ "elevated": {
48
+ "$ref": "#/definitions/AbstractColor"
49
+ }
50
+ },
51
+ "required": ["base", "elevated"],
52
+ "additionalProperties": false
53
+ },
54
+ "LightDarkColor": {
55
+ "type": "object",
56
+ "properties": {
57
+ "light": {
58
+ "$ref": "#/definitions/AbstractColor"
59
+ },
60
+ "dark": {
61
+ "$ref": "#/definitions/AbstractColor"
62
+ }
63
+ },
64
+ "required": ["light", "dark"],
65
+ "additionalProperties": false
66
+ }
67
+ },
68
+ "properties": {
69
+ "access_level": {
70
+ "type": "string",
71
+ "description": "Access level of the generated Swift code.",
72
+ "enum": [
73
+ "internal",
74
+ "public"
75
+ ]
76
+ },
77
+ "system_name": {
78
+ "type": "string",
79
+ "description": "Name of the design system or theme."
80
+ },
81
+ "output_path": {
82
+ "type": "string",
83
+ "minLength": 1,
84
+ "description": "Path of generated Swift file."
85
+ },
86
+ "colors": {
87
+ "type": "object",
88
+ "description": "Key-value pairs of colors.",
89
+ "patternProperties": {
90
+ "^.*$": {
91
+ "anyOf": [
92
+ {
93
+ "$ref": "#/definitions/AbstractColor"
94
+ }
95
+ ]
96
+ }
97
+ },
98
+ "additionalProperties": false
99
+ }
100
+ },
101
+ "required": [
102
+ "output_path",
103
+ "colors"
104
+ ]
105
+ }
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json_schemer"
4
+
5
+ module Stylegen
6
+ class Validator
7
+ def valid?(config)
8
+ schema.valid?(config)
9
+ end
10
+
11
+ def validate(config)
12
+ errors = []
13
+
14
+ schema.validate(config).each do |v|
15
+ errors << JSONSchemer::Errors.pretty(v) unless v["type"] == "schema"
16
+ end
17
+
18
+ errors
19
+ end
20
+
21
+ private
22
+
23
+ def schema
24
+ @schema ||= JSONSchemer.schema(File.read(File.join(__dir__, "schema.json")))
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stylegen
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./lib/stylegen/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "stylegen"
7
+ s.version = Stylegen::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ramon Torres"]
10
+ s.email = ["raymondjavaxx@gmail.com"]
11
+ s.homepage = "https://github.com/raymondjavaxx/stylegen"
12
+ s.description = s.summary = "Tool for generating styling code for iOS apps"
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+ s.license = "MIT"
18
+
19
+ s.add_runtime_dependency "dry-inflector", ">= 0.2.0"
20
+ s.add_runtime_dependency "json_schemer", ">= 0.2.0"
21
+
22
+ s.add_development_dependency "bundler"
23
+ s.add_development_dependency "minitest", ">= 5.14.0"
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "rubocop"
26
+ s.add_development_dependency "rubocop-minitest"
27
+ s.add_development_dependency "rubocop-rake"
28
+
29
+ s.required_ruby_version = ">= 2.4.0"
30
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem "minitest"
4
+
5
+ require "minitest/pride"
6
+ require "minitest/autorun"
7
+
8
+ require_relative "../lib/stylegen"
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helper"
4
+
5
+ class TestBaseElevatedColor < MiniTest::Test
6
+ def test_to_string
7
+ color = Stylegen::BaseElevatedColor.new(
8
+ Stylegen::Color.from_hex("#000000"),
9
+ Stylegen::Color.from_hex("#333333")
10
+ )
11
+
12
+ # Default indentation
13
+
14
+ expected = <<~CODE.chomp
15
+ ThemeColor(
16
+ base: ThemeColor(white: 0.0, alpha: 1.0),
17
+ elevated: ThemeColor(white: 0.2, alpha: 1.0)
18
+ )
19
+ CODE
20
+
21
+ assert_equal expected, color.to_s("ThemeColor")
22
+
23
+ # Additional indentation
24
+
25
+ expected = <<~CODE.chomp
26
+ ThemeColor(
27
+ base: ThemeColor(white: 0.0, alpha: 1.0),
28
+ elevated: ThemeColor(white: 0.2, alpha: 1.0)
29
+ )
30
+ CODE
31
+
32
+ assert_equal expected, color.to_s("ThemeColor", 4)
33
+ end
34
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helper"
4
+
5
+ class TestColor < MiniTest::Test
6
+ def test_parsing
7
+ color = Stylegen::Color.from_hex("#FF8000")
8
+ assert_equal 1.0, color.red
9
+ assert_equal 0.5, color.green
10
+ assert_equal 0.0, color.blue
11
+ assert_equal 1.0, color.alpha
12
+
13
+ # Optional pound sign
14
+ color = Stylegen::Color.from_hex("FF8000")
15
+ assert_equal 1.0, color.red
16
+ assert_equal 0.5, color.green
17
+ assert_equal 0.0, color.blue
18
+ assert_equal 1.0, color.alpha
19
+
20
+ # Specify alpha
21
+ color = Stylegen::Color.from_hex("#FF8000", 0.5)
22
+ assert_equal 0.5, color.alpha
23
+ end
24
+
25
+ def test_parsing_shorthand_syntax
26
+ color = Stylegen::Color.from_hex("#FC0")
27
+ assert_equal 1.0, color.red
28
+ assert_equal 0.8, color.green
29
+ assert_equal 0.0, color.blue
30
+ assert_equal 1.0, color.alpha
31
+
32
+ # Optional pound sign
33
+ color = Stylegen::Color.from_hex("FC0")
34
+ assert_equal 1.0, color.red
35
+ assert_equal 0.8, color.green
36
+ assert_equal 0.0, color.blue
37
+ assert_equal 1.0, color.alpha
38
+ end
39
+
40
+ def test_grayscale
41
+ color = Stylegen::Color.new(1, 1, 1, 1)
42
+ assert color.grayscale?
43
+
44
+ color = Stylegen::Color.new(1, 1, 0.9, 1)
45
+ refute color.grayscale?
46
+ end
47
+
48
+ def test_to_string
49
+ color = Stylegen::Color.from_hex("#00FF00")
50
+ expected = "ThemeColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0)"
51
+ assert_equal expected, color.to_s("ThemeColor")
52
+
53
+ # Grayscale
54
+ color = Stylegen::Color.from_hex("#FFFFFF")
55
+ expected = "ThemeColor(white: 1.0, alpha: 1.0)"
56
+ assert_equal expected, color.to_s("ThemeColor")
57
+ end
58
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helper"
4
+
5
+ class TestLightDarkColor < MiniTest::Test
6
+ def test_to_string
7
+ color = Stylegen::LightDarkColor.new(
8
+ Stylegen::Color.from_hex("#FFFFFF"),
9
+ Stylegen::Color.from_hex("#333333")
10
+ )
11
+
12
+ # Default indentation
13
+
14
+ expected = <<~CODE.chomp
15
+ ThemeColor(
16
+ light: ThemeColor(white: 1.0, alpha: 1.0),
17
+ dark: ThemeColor(white: 0.2, alpha: 1.0)
18
+ )
19
+ CODE
20
+
21
+ assert_equal expected, color.to_s("ThemeColor")
22
+
23
+ # Additional indentation
24
+
25
+ expected = <<~CODE.chomp
26
+ ThemeColor(
27
+ light: ThemeColor(white: 1.0, alpha: 1.0),
28
+ dark: ThemeColor(white: 0.2, alpha: 1.0)
29
+ )
30
+ CODE
31
+
32
+ assert_equal expected, color.to_s("ThemeColor", 4)
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stylegen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ramon Torres
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-inflector
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: json_schemer
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 5.14.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 5.14.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Tool for generating styling code for iOS apps
126
+ email:
127
+ - raymondjavaxx@gmail.com
128
+ executables:
129
+ - stylegen
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".github/workflows/ci.yml"
134
+ - ".gitignore"
135
+ - ".rubocop.yml"
136
+ - Gemfile
137
+ - Gemfile.lock
138
+ - LICENSE
139
+ - README.md
140
+ - Rakefile
141
+ - bin/stylegen
142
+ - lib/stylegen.rb
143
+ - lib/stylegen/colors.rb
144
+ - lib/stylegen/colors/base_elevated_color.rb
145
+ - lib/stylegen/colors/color.rb
146
+ - lib/stylegen/colors/light_dark_color.rb
147
+ - lib/stylegen/data.rb
148
+ - lib/stylegen/generator.rb
149
+ - lib/stylegen/schema.json
150
+ - lib/stylegen/validator.rb
151
+ - lib/stylegen/version.rb
152
+ - stylegen.gemspec
153
+ - test/helper.rb
154
+ - test/test_base_elevated_color.rb
155
+ - test/test_color.rb
156
+ - test/test_light_dark_color.rb
157
+ homepage: https://github.com/raymondjavaxx/stylegen
158
+ licenses:
159
+ - MIT
160
+ metadata: {}
161
+ post_install_message:
162
+ rdoc_options: []
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: 2.4.0
170
+ required_rubygems_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ requirements: []
176
+ rubyforge_project:
177
+ rubygems_version: 2.7.6
178
+ signing_key:
179
+ specification_version: 4
180
+ summary: Tool for generating styling code for iOS apps
181
+ test_files:
182
+ - test/helper.rb
183
+ - test/test_base_elevated_color.rb
184
+ - test/test_color.rb
185
+ - test/test_light_dark_color.rb