fino 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 923a928e308816fef20053f1f35fff93f8fbc43e48dcc80e7ef83eab6a69a3bd
4
+ data.tar.gz: ff5af3d11e4184cb45fa06039514722596b2237be3c42e00be1b87fee3c401d1
5
+ SHA512:
6
+ metadata.gz: 02ebcf4c01d917a775909b9d9bfcca9f7840aa0941a9339f885b491fa91337e9367f3692de7cc0f6ba75a27ce9cfebed221014aa50fd1079eb1cdbe97508353d
7
+ data.tar.gz: 308a664811806d793796208a7d0dfe736c1d20f8e4ba3bda8d2bebb65e420872669127cd05c214e877026df855cba6c0d9d7189b317f70b3b9599d7996054cc8
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # Fino
2
+
3
+ ```ruby
4
+ Fino.value(:retries_amount)
5
+ Fino.value(:http_read_timeout, :service_a)
6
+ ```
7
+
8
+ ## TODO
9
+
10
+ - Basic validations (presence, range, numericality)
11
+ - Enum setting type
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Adapters::Memory
4
+ include Fino::Adapter
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fino::Adapter
4
+ def read(setting_definition)
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def read_multi(setting_definitions)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def write(setting_definition, value)
13
+ raise NotImplementedError
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Cache::Memory
4
+ include Fino::Cache
5
+
6
+ def initialize(expires_in:)
7
+ @hash = {}
8
+ @expirator = Fino::Expirator.new(ttl: expires_in)
9
+ end
10
+
11
+ def fetch(key, &)
12
+ @hash.fetch(key, &)
13
+ ensure
14
+ @expirator.when_ready do
15
+ @hash.clear
16
+ end
17
+ end
18
+
19
+ def write(key, value)
20
+ @hash[key] = value
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Cache::Null
4
+ include Fino::Cache
5
+
6
+ def fetch(_key)
7
+ yield
8
+ end
9
+ end
data/lib/fino/cache.rb ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fino::Cache
4
+ def fetch(key, &)
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def write(key, value)
9
+ raise NotImplementedError
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Configuration
4
+ attr_reader :registry, :adapter_builder_block, :cache_builder_block
5
+
6
+ def initialize(registry)
7
+ @registry = registry
8
+ end
9
+
10
+ def adapter(&block)
11
+ @adapter_builder_block = block
12
+ end
13
+
14
+ def cache(&block)
15
+ @cache_builder_block = block
16
+ end
17
+
18
+ def settings(&)
19
+ Fino::Registry::DSL.new(registry).instance_eval(&)
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Engine < Rails::Engine
4
+ isolate_namespace Fino
5
+ end
data/lib/fino/error.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Fino::Error = Class.new(StandardError)
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Expirator
4
+ def initialize(ttl:)
5
+ @ttl = ttl
6
+ reset_timestamp
7
+ end
8
+
9
+ def when_ready
10
+ return if current_timestamp - stored_timestamp < ttl
11
+
12
+ yield
13
+
14
+ reset_timestamp
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :stored_timestamp, :ttl
20
+
21
+ def reset_timestamp
22
+ @stored_timestamp = current_timestamp
23
+ end
24
+
25
+ def current_timestamp
26
+ Time.now.to_i
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fino::Ext::Hash
4
+ refine Hash do
5
+ def deep_set(value, *path)
6
+ item = path.pop
7
+
8
+ if path.empty?
9
+ self[item] = value
10
+ else
11
+ (self[item] ||= {}).deep_set(value, *path)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ class Fino::Library
6
+ def initialize(configuration)
7
+ @configuration = configuration
8
+ end
9
+
10
+ def value(*setting_path)
11
+ setting(*setting_path).value
12
+ end
13
+
14
+ def setting(*setting_path)
15
+ pipeline.read(build_setting_definition(*setting_path))
16
+ end
17
+
18
+ def all
19
+ pipeline.read_multi(configuration.registry.setting_definitions)
20
+ end
21
+
22
+ def set(value, *setting_path)
23
+ pipeline.write(value, build_setting_definition(*setting_path))
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :configuration
29
+
30
+ def build_setting_definition(*setting_path)
31
+ configuration.registry.fetch(*setting_path)
32
+ end
33
+
34
+ def pipeline
35
+ @pipeline ||= Fino::Pipeline.new.tap do |p|
36
+ p.use Fino::Pipeline::Cache.new(cache) if cache
37
+ p.use Fino::Pipeline::Adapter.new(adapter)
38
+ end
39
+ end
40
+
41
+ def cache
42
+ return @cache if defined?(@cache)
43
+
44
+ @cache = configuration.cache_builder_block&.call
45
+ end
46
+
47
+ def adapter
48
+ @adapter ||= configuration.adapter_builder_block.call
49
+ end
50
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Pipeline::Adapter
4
+ def initialize(adapter)
5
+ @adapter = adapter
6
+ end
7
+
8
+ def read(setting_definition)
9
+ to_setting(setting_definition, adapter.read(setting_definition))
10
+ end
11
+
12
+ def read_multi(setting_definitions)
13
+ setting_definitions.zip(adapter.read_multi(setting_definitions)).map do |definition, raw_data|
14
+ to_setting(definition, raw_data)
15
+ end
16
+ end
17
+
18
+ def write(setting_definition, value)
19
+ adapter.write(setting_definition, value)
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :adapter
25
+
26
+ def to_setting(setting_definition, raw_adapter_data)
27
+ raw_value = adapter.fetch_value_from(raw_adapter_data)
28
+
29
+ setting_definition.type_class.build(
30
+ setting_definition,
31
+ raw_value,
32
+ **raw_adapter_data
33
+ )
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Pipeline::Cache
4
+ def initialize(cache)
5
+ @cache = cache
6
+ end
7
+
8
+ def read(setting_definition, &)
9
+ cache.fetch(setting_definition.key, &)
10
+ end
11
+
12
+ def read_multi(setting_definitions, &); end
13
+
14
+ def write(setting_definition, value)
15
+ cache.write(setting_definition.key, setting_definition.type_class.build(setting_definition, value))
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :cache
21
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Pipeline
4
+ def initialize(pipes = [])
5
+ @pipes = pipes
6
+ end
7
+
8
+ def use(pipe)
9
+ @pipes << pipe
10
+ end
11
+
12
+ def read(setting_definition)
13
+ read_pipeline(setting_definition)
14
+ end
15
+
16
+ def read_multi(setting_definitions)
17
+ @pipes.each do |pipe|
18
+ settings = pipe.read_multi(setting_definitions)
19
+ return settings if settings
20
+ end
21
+ end
22
+
23
+ def write(value, setting_definition)
24
+ @pipes.each do |pipe|
25
+ pipe.write(setting_definition, value)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def read_pipeline(setting_definition, pipe_index = 0)
32
+ @pipes[pipe_index]&.read(setting_definition) do
33
+ read_pipeline(setting_definition, pipe_index + 1)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Redis::Adapter
4
+ include Fino::Adapter
5
+
6
+ DEFAULT_REDIS_NAMESPACE = "fino"
7
+ VALUE_KEY = "v"
8
+
9
+ def initialize(redis, namespace: DEFAULT_REDIS_NAMESPACE)
10
+ @redis = redis
11
+ @redis_namespace = namespace
12
+ end
13
+
14
+ def read(setting_definition)
15
+ redis.hgetall(redis_key_for(setting_definition))
16
+ end
17
+
18
+ def write(setting_definition, value)
19
+ redis.hset(redis_key_for(setting_definition), VALUE_KEY, setting_definition.type_class.serialize(value))
20
+ end
21
+
22
+ def read_multi(setting_definitions)
23
+ keys = setting_definitions.map { |definition| redis_key_for(definition) }
24
+
25
+ redis.pipelined do |pipeline|
26
+ keys.each { |key| pipeline.hgetall(key) }
27
+ end
28
+ end
29
+
30
+ def fetch_value_from(raw_adapter_data)
31
+ raw_adapter_data.key?(VALUE_KEY) ? raw_adapter_data.delete(VALUE_KEY) : Fino::Setting::UNSET_VALUE
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :redis, :redis_namespace
37
+
38
+ def redis_key_for(setting_definition)
39
+ "#{redis_namespace}:#{setting_definition.path.join(':')}"
40
+ end
41
+ end
data/lib/fino/redis.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fino"
4
+ require "redis"
5
+
6
+ module Fino::Redis
7
+ end
8
+
9
+ require "fino/redis/adapter"
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Registry
4
+ class DSL
5
+ class SectionDSL
6
+ def initialize(section_name, _options, registry)
7
+ @section_name = section_name
8
+ @registry = registry
9
+ end
10
+
11
+ def setting(setting_name, type, **)
12
+ @registry.register(
13
+ Fino::SettingDefinition.new(
14
+ type: type,
15
+ setting_name: setting_name,
16
+ section_name: @section_name,
17
+ **
18
+ )
19
+ )
20
+ end
21
+ end
22
+
23
+ def initialize(registry)
24
+ @registry = registry
25
+ end
26
+
27
+ def setting(setting_name, type, **)
28
+ @registry.register(
29
+ Fino::SettingDefinition.new(
30
+ type: type,
31
+ setting_name: setting_name,
32
+ **
33
+ )
34
+ )
35
+ end
36
+
37
+ def section(section_name, options = {}, &)
38
+ SectionDSL.new(section_name, options, @registry).instance_eval(&)
39
+ end
40
+ end
41
+
42
+ UnknownSetting = Class.new(Fino::Error)
43
+
44
+ using Fino::Ext::Hash
45
+
46
+ attr_reader :setting_definitions_by_path, :setting_definitions
47
+
48
+ def initialize
49
+ @setting_definitions_by_path = {}
50
+ @setting_definitions = []
51
+ end
52
+
53
+ def fetch(*path)
54
+ @setting_definitions_by_path.dig(*path.reverse).tap do |definition|
55
+ raise UnknownSetting, "Unknown setting: #{path.compact.join('.')}" unless definition
56
+ end
57
+ end
58
+
59
+ def register(setting_definition)
60
+ @setting_definitions << setting_definition
61
+
62
+ @setting_definitions_by_path.deep_set(setting_definition, *setting_definition.path)
63
+ end
64
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fino::Setting
4
+ UNSET_VALUE = Object.new.freeze
5
+
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def serialize(value)
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def deserialize(raw_value)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def build(setting_definition, raw_value, *options)
20
+ new(
21
+ setting_definition,
22
+ raw_value.equal?(UNSET_VALUE) ? setting_definition.options[:default] : deserialize(raw_value),
23
+ *options
24
+ )
25
+ end
26
+ end
27
+
28
+ attr_reader :definition, :value
29
+
30
+ def initialize(definition, value, **options)
31
+ @definition = definition
32
+ @value = value
33
+
34
+ @options = options
35
+ end
36
+
37
+ def name
38
+ definition.setting_name
39
+ end
40
+
41
+ def section_name
42
+ definition.section_name
43
+ end
44
+
45
+ def default
46
+ definition.default
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::SettingDefinition
4
+ attr_reader :setting_name, :section_name, :type, :options
5
+
6
+ def initialize(type:, setting_name:, section_name: nil, **options)
7
+ @setting_name = setting_name
8
+ @section_name = section_name
9
+ @type = type
10
+ @options = options
11
+ end
12
+
13
+ def type_class
14
+ case type
15
+ when :string
16
+ Fino::Settings::String
17
+ when :integer
18
+ Fino::Settings::Integer
19
+ when :float
20
+ Fino::Settings::Float
21
+ when :boolean
22
+ Fino::Settings::Boolean
23
+ else
24
+ raise "Unknown type #{type}"
25
+ end
26
+ end
27
+
28
+ def default
29
+ options[:default]
30
+ end
31
+
32
+ def path
33
+ @path ||= [setting_name, section_name].compact
34
+ end
35
+
36
+ def key
37
+ path.join("_")
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Settings::Boolean
4
+ include Fino::Setting
5
+
6
+ class << self
7
+ def serialize(value)
8
+ value ? "1" : "0"
9
+ end
10
+
11
+ def deserialize(raw_value)
12
+ raw_value == "1"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Settings::Float
4
+ include Fino::Setting
5
+
6
+ class << self
7
+ def serialize(value)
8
+ value.to_s
9
+ end
10
+
11
+ def deserialize(raw_value)
12
+ raw_value.to_f
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Settings::Integer
4
+ include Fino::Setting
5
+
6
+ class << self
7
+ def serialize(value)
8
+ value.to_s
9
+ end
10
+
11
+ def deserialize(raw_value)
12
+ raw_value.to_i
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Settings::Section
4
+ attr_reader :name, :label, :settings
5
+
6
+ def initialize(name = nil, label: nil)
7
+ @name = name
8
+ @label = label
9
+
10
+ @settings = {}
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::Settings::String
4
+ include Fino::Setting
5
+
6
+ class << self
7
+ def serialize(value)
8
+ value
9
+ end
10
+
11
+ def deserialize(raw_value)
12
+ raw_value
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::UI::ApplicationController < ActionController::Base
4
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fino::UI::SettingsController < Fino::UI::ApplicationController
4
+ def index
5
+ @settings = Fino.library.all
6
+ end
7
+
8
+ def edit
9
+ setting_path = parse_setting_path(params[:key])
10
+
11
+ @setting = Fino.setting(*setting_path)
12
+ end
13
+
14
+ def update
15
+ begin
16
+ # Parse the key to create the setting path
17
+ setting_path = parse_setting_path(params[:key])
18
+
19
+ # Update the setting using the correct API
20
+ Fino.set(params[:value], *setting_path)
21
+
22
+ redirect_to root_path, notice: "Setting updated successfully"
23
+ rescue Fino::Registry::UnknownSetting
24
+ redirect_to root_path, alert: "Setting not found"
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def parse_setting_path(key)
31
+ key.split('.').map(&:to_sym).reverse
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
4
+ inflect.acronym "UI"
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Fino::UI::Engine.routes.draw do
4
+ root to: "settings#index"
5
+
6
+ resources :settings, only: [:index, :edit, :update], param: :key, constraints: { key: /[^\/]+/ }
7
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fino-ui"
4
+
5
+ class Fino::UI::Engine < Rails::Engine
6
+ isolate_namespace Fino::UI
7
+
8
+ paths["app"] << root.join("lib", "fino", "ui", "app")
9
+ paths["config/initializers"] << root.join("lib", "fino", "ui", "config", "initializers")
10
+
11
+ initializer "fino.ui.append_view_paths" do |_app|
12
+ ActiveSupport.on_load :action_controller do
13
+ prepend_view_path Fino::UI::Engine.root.join("lib", "fino", "ui", "app", "views")
14
+ end
15
+ end
16
+
17
+ initializer "fino.ui.load_routes", before: :add_routing_paths do |app|
18
+ custom_routes = root.join("lib", "fino", "ui", "config", "routes.rb")
19
+ app.routes_reloader.paths << custom_routes.to_s
20
+ end
21
+ end
data/lib/fino/ui.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fino"
4
+
5
+ module Fino::UI
6
+ end
7
+
8
+ require "fino/ui/engine"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fino
4
+ VERSION = "1.0.0"
5
+ end
data/lib/fino-redis.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fino/redis"
data/lib/fino-ui.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fino/ui"
data/lib/fino.rb ADDED
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "zeitwerk"
5
+
6
+ module Fino
7
+ module Configurable
8
+ def configure(&)
9
+ configuration.instance_eval(&)
10
+ end
11
+
12
+ private
13
+
14
+ def configuration
15
+ @configuration ||= Fino::Configuration.new(registry)
16
+ end
17
+ end
18
+
19
+ module SettingsAccessible
20
+ extend Forwardable
21
+
22
+ def_delegators :library,
23
+ :value,
24
+ :setting,
25
+ :all,
26
+ :set
27
+
28
+ module_function
29
+
30
+ def library
31
+ raise NotImplementedError
32
+ end
33
+ end
34
+
35
+ extend Configurable
36
+ extend SettingsAccessible
37
+
38
+ module_function
39
+
40
+ def library
41
+ Thread.current[:fino_library] ||= Fino::Library.new(configuration)
42
+ end
43
+
44
+ def registry
45
+ @registry ||= Fino::Registry.new
46
+ end
47
+
48
+ def root
49
+ File.expand_path("..", __dir__)
50
+ end
51
+ end
52
+
53
+ Zeitwerk::Loader.for_gem.tap do |l|
54
+ root_relative_path = ->(path) { File.join(Fino.root, path) }
55
+
56
+ l.ignore(
57
+ [
58
+ root_relative_path.call("lib/fino-ui.rb"),
59
+ root_relative_path.call("lib/fino/ui.rb"),
60
+ root_relative_path.call("lib/fino/ui/"),
61
+
62
+ root_relative_path.call("lib/fino-redis.rb"),
63
+ root_relative_path.call("lib/fino/redis.rb"),
64
+ root_relative_path.call("lib/fino/redis/"),
65
+
66
+ root_relative_path.call("lib/fino/engine.rb")
67
+ ]
68
+ )
69
+ end.setup
70
+
71
+ require "fino/engine" if defined?(Rails)
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fino
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Egor Iskrenkov
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: zeitwerk
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.5'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.5'
26
+ email:
27
+ - egor@iskrenkov.me
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - README.md
33
+ - lib/fino-redis.rb
34
+ - lib/fino-ui.rb
35
+ - lib/fino.rb
36
+ - lib/fino/adapter.rb
37
+ - lib/fino/adapter/memory.rb
38
+ - lib/fino/cache.rb
39
+ - lib/fino/cache/memory.rb
40
+ - lib/fino/cache/null.rb
41
+ - lib/fino/configuration.rb
42
+ - lib/fino/engine.rb
43
+ - lib/fino/error.rb
44
+ - lib/fino/expirator.rb
45
+ - lib/fino/ext/hash.rb
46
+ - lib/fino/library.rb
47
+ - lib/fino/pipeline.rb
48
+ - lib/fino/pipeline/adapter.rb
49
+ - lib/fino/pipeline/cache.rb
50
+ - lib/fino/redis.rb
51
+ - lib/fino/redis/adapter.rb
52
+ - lib/fino/registry.rb
53
+ - lib/fino/setting.rb
54
+ - lib/fino/setting_definition.rb
55
+ - lib/fino/settings/boolean.rb
56
+ - lib/fino/settings/float.rb
57
+ - lib/fino/settings/integer.rb
58
+ - lib/fino/settings/section.rb
59
+ - lib/fino/settings/string.rb
60
+ - lib/fino/ui.rb
61
+ - lib/fino/ui/app/controllers/fino/ui/application_controller.rb
62
+ - lib/fino/ui/app/controllers/fino/ui/settings_controller.rb
63
+ - lib/fino/ui/config/initializers/inflections.rb
64
+ - lib/fino/ui/config/routes.rb
65
+ - lib/fino/ui/engine.rb
66
+ - lib/fino/version.rb
67
+ homepage: https://github.com/eiskrenkov/fino
68
+ licenses: []
69
+ metadata:
70
+ homepage_uri: https://github.com/eiskrenkov/fino
71
+ source_code_uri: https://github.com/eiskrenkov/fino
72
+ rubygems_mfa_required: 'true'
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 3.0.0
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.6.9
88
+ specification_version: 4
89
+ summary: Elegant & performant settings engine for Ruby and Rails
90
+ test_files: []