flexite 0.0.2

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.
Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +12 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  6. data/app/assets/fonts/glyphicons-halflings-regular.svg +288 -0
  7. data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  8. data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  9. data/app/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
  10. data/app/assets/images/flexite/glyphicons-halflings-white.png +0 -0
  11. data/app/assets/images/flexite/glyphicons-halflings.png +0 -0
  12. data/app/assets/javascripts/flexite/application.js +18 -0
  13. data/app/assets/javascripts/flexite/bootstrap.min.js +7 -0
  14. data/app/assets/javascripts/flexite/common.js.erb +2 -0
  15. data/app/assets/javascripts/flexite/jquery.min.js +2 -0
  16. data/app/assets/javascripts/flexite/tree.js.erb +83 -0
  17. data/app/assets/javascripts/flexite/treeview.js +1335 -0
  18. data/app/assets/stylesheets/flexite/application.css +29 -0
  19. data/app/assets/stylesheets/flexite/bootstrap-treeview.min.css +1 -0
  20. data/app/assets/stylesheets/flexite/bootstrap.min.css +5 -0
  21. data/app/assets/stylesheets/flexite/configs.css +8 -0
  22. data/app/assets/stylesheets/flexite/entries.css +4 -0
  23. data/app/assets/stylesheets/flexite/tree.css +21 -0
  24. data/app/assets/stylesheets/scaffold.css +56 -0
  25. data/app/controllers/flexite/application_controller.rb +25 -0
  26. data/app/controllers/flexite/configs_controller.rb +61 -0
  27. data/app/controllers/flexite/entries_controller.rb +82 -0
  28. data/app/factories/flexite/base_factory.rb +7 -0
  29. data/app/factories/flexite/service_factory.rb +19 -0
  30. data/app/forms/flexite/base_form.rb +24 -0
  31. data/app/forms/flexite/config/form.rb +12 -0
  32. data/app/forms/flexite/entry/array_form.rb +11 -0
  33. data/app/forms/flexite/entry/form.rb +16 -0
  34. data/app/helpers/flexite/application_helper.rb +15 -0
  35. data/app/helpers/flexite/configs_helper.rb +4 -0
  36. data/app/helpers/flexite/entries_helper.rb +46 -0
  37. data/app/models/flexite/arr_entry.rb +35 -0
  38. data/app/models/flexite/bool_entry.rb +19 -0
  39. data/app/models/flexite/config.rb +64 -0
  40. data/app/models/flexite/entry.rb +30 -0
  41. data/app/models/flexite/int_entry.rb +13 -0
  42. data/app/models/flexite/str_entry.rb +2 -0
  43. data/app/models/flexite/sym_entry.rb +17 -0
  44. data/app/services/flexite/action_service/result.rb +44 -0
  45. data/app/services/flexite/action_service.rb +30 -0
  46. data/app/services/flexite/config/create_service.rb +25 -0
  47. data/app/services/flexite/config/update_service.rb +28 -0
  48. data/app/services/flexite/data/hash.rb +17 -0
  49. data/app/services/flexite/data/migrators/yaml.rb +62 -0
  50. data/app/services/flexite/data/new.rb +87 -0
  51. data/app/services/flexite/entry/array_create_service.rb +69 -0
  52. data/app/services/flexite/entry/array_update_service.rb +69 -0
  53. data/app/services/flexite/entry/create_service.rb +31 -0
  54. data/app/services/flexite/entry/destroy_array_entry_service.rb +25 -0
  55. data/app/services/flexite/entry/destroy_service.rb +22 -0
  56. data/app/services/flexite/entry/update_service.rb +26 -0
  57. data/app/simple_form/array_input.rb +13 -0
  58. data/app/views/flexite/application/index.html.haml +14 -0
  59. data/app/views/flexite/configs/_form.html.haml +7 -0
  60. data/app/views/flexite/configs/create.js.haml +3 -0
  61. data/app/views/flexite/configs/edit.js.haml +1 -0
  62. data/app/views/flexite/configs/index.json.erb +10 -0
  63. data/app/views/flexite/configs/new.js.haml +1 -0
  64. data/app/views/flexite/configs/update.js.haml +2 -0
  65. data/app/views/flexite/entries/_form.html.haml +11 -0
  66. data/app/views/flexite/entries/_new_array_entry_form.html.haml +7 -0
  67. data/app/views/flexite/entries/_popup.html.haml +18 -0
  68. data/app/views/flexite/entries/_types_dropdown.html.haml +8 -0
  69. data/app/views/flexite/entries/create.js.haml +4 -0
  70. data/app/views/flexite/entries/destroy.js.haml +4 -0
  71. data/app/views/flexite/entries/destroy_array_entry.js.haml +6 -0
  72. data/app/views/flexite/entries/edit.js.haml +1 -0
  73. data/app/views/flexite/entries/new.js.haml +1 -0
  74. data/app/views/flexite/entries/new_array_entry.js.haml +1 -0
  75. data/app/views/flexite/entries/select_type.js.haml +1 -0
  76. data/app/views/flexite/entries/types/_arr_entry.html.haml +19 -0
  77. data/app/views/flexite/entries/types/_bool_entry.html.haml +4 -0
  78. data/app/views/flexite/entries/types/_int_entry.html.haml +4 -0
  79. data/app/views/flexite/entries/types/_str_entry.html.haml +4 -0
  80. data/app/views/flexite/entries/types/_sym_entry.html.haml +1 -0
  81. data/app/views/flexite/entries/update.js.haml +1 -0
  82. data/app/views/flexite/shared/_messages.html.haml +5 -0
  83. data/app/views/flexite/shared/_show_flash.js.haml +5 -0
  84. data/app/views/layouts/flexite/application.html.haml +11 -0
  85. data/config/initializers/simple_form.rb +143 -0
  86. data/config/initializers/simple_form_bootstrap.rb +43 -0
  87. data/config/locales/simple_form.en.yml +26 -0
  88. data/config/routes.rb +17 -0
  89. data/db/migrate/20180503102555_create_flexite_configs.rb +14 -0
  90. data/db/migrate/20180503103109_create_flexite_entries.rb +14 -0
  91. data/lib/flexite/cached_node.rb +19 -0
  92. data/lib/flexite/configuration.rb +24 -0
  93. data/lib/flexite/engine.rb +18 -0
  94. data/lib/flexite/flexy.rb +13 -0
  95. data/lib/flexite/nodes_hash.rb +5 -0
  96. data/lib/flexite/version.rb +3 -0
  97. data/lib/flexite.rb +44 -0
  98. data/lib/tasks/flexite_tasks.rake +20 -0
  99. data/test/dummy/README.rdoc +261 -0
  100. data/test/dummy/Rakefile +7 -0
  101. data/test/dummy/app/assets/javascripts/application.js +15 -0
  102. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  103. data/test/dummy/app/controllers/application_controller.rb +3 -0
  104. data/test/dummy/app/helpers/application_helper.rb +2 -0
  105. data/test/dummy/config/application.rb +59 -0
  106. data/test/dummy/config/application.yml +599 -0
  107. data/test/dummy/config/boot.rb +10 -0
  108. data/test/dummy/config/database.yml +25 -0
  109. data/test/dummy/config/environment.rb +5 -0
  110. data/test/dummy/config/environments/development.rb +40 -0
  111. data/test/dummy/config/environments/production.rb +67 -0
  112. data/test/dummy/config/environments/test.rb +37 -0
  113. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  114. data/test/dummy/config/initializers/flexite.rb +5 -0
  115. data/test/dummy/config/initializers/inflections.rb +15 -0
  116. data/test/dummy/config/initializers/mime_types.rb +5 -0
  117. data/test/dummy/config/initializers/secret_token.rb +7 -0
  118. data/test/dummy/config/initializers/session_store.rb +8 -0
  119. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  120. data/test/dummy/config/locales/en.yml +5 -0
  121. data/test/dummy/config/routes.rb +3 -0
  122. data/test/dummy/config.ru +4 -0
  123. data/test/dummy/db/development.sqlite3 +0 -0
  124. data/test/dummy/db/schema.rb +39 -0
  125. data/test/dummy/db/seeds.rb +3 -0
  126. data/test/dummy/db/test.sqlite3 +0 -0
  127. data/test/dummy/log/development.log +86588 -0
  128. data/test/dummy/public/404.html +26 -0
  129. data/test/dummy/public/422.html +26 -0
  130. data/test/dummy/public/500.html +25 -0
  131. data/test/dummy/public/favicon.ico +0 -0
  132. data/test/dummy/script/rails +6 -0
  133. data/test/dummy/tmp/cache/assets/C67/060/sprockets%2Ffaf176441f0544dd2b51901280044b40 +0 -0
  134. data/test/dummy/tmp/cache/assets/C9D/530/sprockets%2Fdcd49c063327c12052812f41c20a8e74 +0 -0
  135. data/test/dummy/tmp/cache/assets/CA3/270/sprockets%2F502b740063f8ec15e7e12811da71c772 +0 -0
  136. data/test/dummy/tmp/cache/assets/CDC/060/sprockets%2F8ff1d307d1b36810549d0829722b7aea +0 -0
  137. data/test/dummy/tmp/cache/assets/CDE/120/sprockets%2F5fd8b3fa3724451579552aed373410ce +0 -0
  138. data/test/dummy/tmp/cache/assets/CF8/980/sprockets%2F4e5077b95460dc34d7c9d7d9880e7b47 +0 -0
  139. data/test/dummy/tmp/cache/assets/D00/4C0/sprockets%2F603c6d7b825c2f4a6422b3d4af4e6203 +0 -0
  140. data/test/dummy/tmp/cache/assets/D00/C40/sprockets%2F999847c008fb4ce26fff5607c39d8358 +0 -0
  141. data/test/dummy/tmp/cache/assets/D09/A30/sprockets%2F2a71e20a2f3544acb51956504cd8d8e9 +0 -0
  142. data/test/dummy/tmp/cache/assets/D0D/E60/sprockets%2F90ea9eaa4671ec2d76703bae31972634 +0 -0
  143. data/test/dummy/tmp/cache/assets/D2A/160/sprockets%2Fbe17d4d0be4b381500e2824bbe273d70 +0 -0
  144. data/test/dummy/tmp/cache/assets/D2E/700/sprockets%2Fb21f85e0940bbcb3a8914c9cb0b07218 +0 -0
  145. data/test/dummy/tmp/cache/assets/D39/CD0/sprockets%2F0e8f6981475e49ea9fe14698fa57e4e9 +0 -0
  146. data/test/dummy/tmp/cache/assets/D40/590/sprockets%2F181dd5673b58f1ec4c89e50028bfad60 +0 -0
  147. data/test/dummy/tmp/cache/assets/D46/870/sprockets%2Fd880bdf72c5d0009b88fda8521439dc8 +0 -0
  148. data/test/dummy/tmp/cache/assets/D48/5F0/sprockets%2Fe6a83afb2d92f4692ffb391b5285a518 +0 -0
  149. data/test/dummy/tmp/cache/assets/D4B/A20/sprockets%2Febde89014596e655c35df9c4a01ee636 +0 -0
  150. data/test/dummy/tmp/cache/assets/D54/A50/sprockets%2Ff49839d906f69fd92904ebac07a3a38e +0 -0
  151. data/test/dummy/tmp/cache/assets/D69/B50/sprockets%2F4186e2787004e19ceb0c4afed46cf04b +0 -0
  152. data/test/dummy/tmp/cache/assets/D6D/C20/sprockets%2F112e96fea93f5f1e31d2077f1cdaf283 +0 -0
  153. data/test/dummy/tmp/cache/assets/D7A/8F0/sprockets%2F8eefc5f9824d950317a5c4a2e68b3c4e +0 -0
  154. data/test/dummy/tmp/cache/assets/DB3/360/sprockets%2F24b1f98ad736884b91d6ebeb2fc68ed8 +0 -0
  155. data/test/dummy/tmp/cache/assets/DD2/E90/sprockets%2Ff01f48c96ba588d15b20dd57ed3ccb7f +0 -0
  156. data/test/dummy/tmp/cache/assets/DEE/0C0/sprockets%2Feedcd74856542eedb5ea3ab1b1502ca4 +0 -0
  157. data/test/dummy/tmp/cache/assets/DF1/210/sprockets%2Ff4fe7dba1445ba1b668aaa1bd34ca984 +0 -0
  158. data/test/dummy/tmp/cache/assets/E44/790/sprockets%2Fefb8d8ea9e97da9d675a8bfa1d5de343 +0 -0
  159. data/test/fixtures/flexite/configs.yml +7 -0
  160. data/test/fixtures/flexite/entries.yml +13 -0
  161. data/test/flexite_test.rb +7 -0
  162. data/test/functional/flexite/configs_controller_test.rb +51 -0
  163. data/test/functional/flexite/entries_controller_test.rb +51 -0
  164. data/test/integration/navigation_test.rb +10 -0
  165. data/test/test_helper.rb +15 -0
  166. data/test/unit/flexite/config_test.rb +9 -0
  167. data/test/unit/flexite/entry_test.rb +9 -0
  168. data/test/unit/helpers/flexite/configs_helper_test.rb +6 -0
  169. data/test/unit/helpers/flexite/entries_helper_test.rb +6 -0
  170. metadata +366 -0
@@ -0,0 +1,24 @@
1
+ class Flexite::BaseForm
2
+ include ActiveModel::Validations
3
+ include ActiveModel::Conversion
4
+ extend ActiveModel::Naming
5
+
6
+ attr_reader :attributes
7
+
8
+ def initialize(attributes = {})
9
+ @attributes = HashWithIndifferentAccess.new
10
+
11
+ attributes.each do |name, value|
12
+ send("#{name}=", value) rescue next
13
+ @attributes[name] = value
14
+ end
15
+ end
16
+
17
+ def persisted?
18
+ respond_to?(:id) && id.present?
19
+ end
20
+
21
+ def new_record?
22
+ !persisted?
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ require_dependency 'flexite/base_form'
2
+
3
+ module Flexite
4
+ class Config::Form < BaseForm
5
+ attr_accessor :id, :name, :config_id, :created_by, :selectable
6
+ validates :name, presence: true
7
+
8
+ def self.model_name
9
+ Config.model_name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Flexite
2
+ class Entry
3
+ class ArrayForm < Form
4
+ attr_accessor :entries, :new_entries
5
+
6
+ def entries
7
+ @entries ||= []
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ require_dependency 'flexite/base_form'
2
+
3
+ module Flexite
4
+ class Entry::Form < BaseForm
5
+ attr_accessor :id, :type, :value, :parent_id, :parent_type
6
+ validates :type, presence: true
7
+
8
+ def self.model_name
9
+ Entry.model_name
10
+ end
11
+
12
+ def view_type
13
+ type.demodulize.underscore
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Flexite
2
+ module ApplicationHelper
3
+ def present(model)
4
+ unless model.respond_to?(:presenter)
5
+ raise "#{model.class.name} is not presentable"
6
+ end
7
+
8
+ yield(model.presenter(self))
9
+ end
10
+
11
+ def back_to_app
12
+ link_to "Back to #{Flexite.config.app_name}", Flexite.config.app_link, class: 'btn btn-default'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module Flexite
2
+ module ConfigsHelper
3
+ end
4
+ end
@@ -0,0 +1,46 @@
1
+ module Flexite
2
+ module EntriesHelper
3
+ ENTRY_TYPE_OPTIONS = [
4
+ ['String', 'Flexite::StrEntry'],
5
+ ['Symbol', 'Flexite::SymEntry'],
6
+ ['Boolean', 'Flexite::BoolEntry'],
7
+ ['Array', 'Flexite::ArrEntry'],
8
+ ['Integer', 'Flexite::IntEntry']
9
+ ].freeze
10
+
11
+ def render_entries(entries, form)
12
+ content_tag :div, id: "array-entries-#{form.options[:index]}" do
13
+ entries.each_with_index do |entry, index|
14
+ concat render_entry(entry, form, index)
15
+ end
16
+ end
17
+ end
18
+
19
+ def entry_type_select(f = nil)
20
+ if f.present?
21
+ f.select :type, options_for_select(ENTRY_TYPE_OPTIONS), {}, class: 'form-control'
22
+ else
23
+ select_tag :new_entry_type, options_for_select(ENTRY_TYPE_OPTIONS), class: 'form-control'
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def render_entry(entry, form, index)
30
+ cache entry do
31
+ entry_form = entry.class.form(entry.form_attributes)
32
+
33
+ concat(form.simple_fields_for(:entries, entry_form, index: index) do |fields|
34
+ delete_link = link_to 'Delete', destroy_array_entries_path(id: entry.id, selector: "#{fields.object_name}-#{index}-#{entry.id}"),
35
+ remote: true, method: :delete, class: 'btn btn-danger'
36
+
37
+ concat(content_tag(:div, id: "#{fields.object_name}-#{index}-#{entry.id}") do
38
+ concat fields.input :id, as: :hidden
39
+ concat fields.input :type, as: :hidden
40
+ concat render "types/#{entry_form.view_type}", f: fields, delete_link: delete_link
41
+ end)
42
+ end)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ module Flexite
2
+ class ArrEntry < Entry
3
+ has_many :entries, as: :parent, dependent: :destroy
4
+
5
+ def value
6
+ entries.select([:id, :value, :type]).map(&:value)
7
+ end
8
+
9
+ def entry=(entry)
10
+ entries << entry
11
+ end
12
+
13
+ def form_attributes
14
+ attributes.merge(entries: form_entries)
15
+ end
16
+
17
+ def self.form(attributes = {})
18
+ Entry::ArrayForm.new(attributes)
19
+ end
20
+
21
+ def self.service(type)
22
+ "arr_entry_#{type}".to_sym
23
+ end
24
+
25
+ private
26
+
27
+ def form_entries
28
+ entries.select([:id, :value, :type, :updated_at])
29
+ end
30
+
31
+ def cast_value
32
+ # value should be blank
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ module Flexite
2
+ class BoolEntry < Entry
3
+ def value
4
+ self[:value].to_i == 1 ? true : false
5
+ end
6
+
7
+ def form
8
+ Entry::Form.new(attributes.merge(value: self[:value].to_i))
9
+ end
10
+
11
+ private
12
+
13
+ def check_value
14
+ unless [1, 0].include?(self[:value].to_i)
15
+ errors.add(:value, 'not a boolean')
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ module Flexite
2
+ class Config < ActiveRecord::Base
3
+ attr_accessible :name
4
+ belongs_to :config, touch: true
5
+ belongs_to :owner, foreign_key: :created_by
6
+ has_one :entry, as: :parent, dependent: :destroy
7
+ has_many :configs, dependent: :destroy
8
+
9
+ scope :not_selectable, -> { select([:id, :name]).where(selectable: false) }
10
+ delegate :value, to: :entry, allow_nil: true
11
+ validates :name, uniqueness: { scope: :config_id }
12
+
13
+ def to_tree_node
14
+ {
15
+ id: id,
16
+ editHref: Engine.routes.url_helpers.edit_config_path(self),
17
+ selfHref: Engine.routes.url_helpers.config_path(self),
18
+ newHref: Engine.routes.url_helpers.new_config_config_path(self),
19
+ text: name,
20
+ dataHref: selectable ? entry_href : configs_href,
21
+ nodes: nodes,
22
+ selectable: true,
23
+ ajaxOnSelect: selectable
24
+ }
25
+ end
26
+
27
+ def self.tree_view(parent_id)
28
+ joins("LEFT JOIN #{table_name} AS configs_#{table_name} ON configs_#{table_name}.config_id = #{table_name}.id")
29
+ .joins("LEFT JOIN #{Entry.table_name} ON #{Entry.table_name}.parent_id = #{table_name}.id AND #{Entry.table_name}.parent_type = '#{model_name}'")
30
+ .select(["#{table_name}.id", "#{table_name}.selectable", "#{table_name}.name", "#{table_name}.updated_at", "COUNT(configs_#{table_name}.id) as nodes_count", "#{Entry.table_name}.id AS entry_id"])
31
+ .where(config_id: parent_id).group("#{table_name}.id")
32
+ end
33
+
34
+ def nodes_count
35
+ self[:nodes_count].to_i
36
+ end
37
+
38
+ def entry_id
39
+ self[:entry_id]
40
+ end
41
+
42
+ def nodes
43
+ if selectable
44
+ return nil
45
+ end
46
+
47
+ nodes_count > 0 ? [] : nil
48
+ end
49
+
50
+ private
51
+
52
+ def entry_href
53
+ if entry_id.present?
54
+ Engine.routes.url_helpers.edit_entry_path(entry_id, format: :js)
55
+ else
56
+ Engine.routes.url_helpers.select_type_entries_path(self, format: :js)
57
+ end
58
+ end
59
+
60
+ def configs_href
61
+ Engine.routes.url_helpers.config_configs_path(self, format: :json)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,30 @@
1
+ module Flexite
2
+ class Entry < ActiveRecord::Base
3
+ belongs_to :parent, polymorphic: true, touch: true
4
+ attr_accessible :value
5
+ before_save :check_value, :cast_value
6
+
7
+ def view_value
8
+ value.to_s
9
+ end
10
+
11
+ def self.form(attributes = {})
12
+ Form.new(attributes)
13
+ end
14
+
15
+ def self.service(type)
16
+ "entry_#{type}".to_sym
17
+ end
18
+
19
+ alias :form_attributes :attributes
20
+
21
+ private
22
+
23
+ def cast_value
24
+ self[:value] = self[:value].to_s
25
+ end
26
+
27
+ def check_value
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ class Flexite::IntEntry < Flexite::Entry
2
+ def value
3
+ self[:value].to_i
4
+ end
5
+
6
+ private
7
+
8
+ def check_value
9
+ self[:value].to_i
10
+ rescue
11
+ errors.add(:value, 'not an Integer')
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ class Flexite::StrEntry < Flexite::Entry
2
+ end
@@ -0,0 +1,17 @@
1
+ class Flexite::SymEntry < Flexite::Entry
2
+ def value
3
+ self[:value].to_sym
4
+ end
5
+
6
+ def view_value
7
+ ":#{value}"
8
+ end
9
+
10
+ private
11
+
12
+ def check_value
13
+ self[:value].to_sym
14
+ rescue
15
+ errors(:value, 'cannot be casted to Symbol')
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ class Flexite::ActionService::Result
2
+ def initialize(options = {})
3
+ @options = options
4
+ @errors = Hash.new { |h, k| h[k] = [] }
5
+ end
6
+
7
+ def succeed?
8
+ @options.fetch(:succeed, true)
9
+ end
10
+
11
+ def failed?
12
+ !succeed?
13
+ end
14
+
15
+ def render?
16
+ @options.fetch(:render, true)
17
+ end
18
+
19
+ def redirect?
20
+ !render?
21
+ end
22
+
23
+ def data
24
+ @options[:data]
25
+ end
26
+
27
+ alias :record :data
28
+
29
+ def add_error(name, value)
30
+ @errors[name] << value
31
+ end
32
+
33
+ def add_errors(name, values)
34
+ @errors[name] += values
35
+ end
36
+
37
+ def endpoint
38
+ @options.fetch(:endpoint, {})
39
+ end
40
+
41
+ def flash
42
+ @options.fetch(:flash, {})
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ class Flexite::ActionService
2
+ def self.inherited(child)
3
+ child.const_set(:Result, Result)
4
+ end
5
+
6
+ def initialize(form, params = {})
7
+ @form = form
8
+ @params = params
9
+ end
10
+
11
+ def call
12
+ raise NotImplementedError
13
+ end
14
+
15
+ protected
16
+
17
+ def success
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def failure
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def save_errors(result)
26
+ @form.errors.messages.each do |key, values|
27
+ result.add_errors(key, values)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ require_dependency 'flexite/action_service'
2
+
3
+ module Flexite
4
+ class Config::CreateService < ActionService
5
+ def call
6
+ if @form.invalid?
7
+ return failure
8
+ end
9
+
10
+ @record = Config.create(@form.attributes, without_protection: true)
11
+ success
12
+ end
13
+
14
+ protected
15
+
16
+ def failure
17
+ Result.new(success: false, endpoint: { status: 400 })
18
+ end
19
+
20
+ def success
21
+ Result.new(flash: { type: :success, message: 'Config was created!' },
22
+ data: { record: @record })
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ module Flexite
2
+ class Config
3
+ class UpdateService < ActionService
4
+ def call
5
+ if @form.invalid?
6
+ return failure
7
+ end
8
+
9
+ @record = Config.find(@form.id)
10
+ @record.config_id = @form.config_id
11
+ @record.selectable = @form.selectable
12
+ @record.name = @form.name
13
+ @record.save
14
+ success
15
+ end
16
+
17
+ protected
18
+
19
+ def failure
20
+ Result.new(success: false, endpoint: { status: 400 })
21
+ end
22
+
23
+ def success
24
+ Result.new(flash: { type: :success, message: 'Config was updated!' }, data: { record: @record })
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ class Flexite::Data::Hash < Hashie::Mash
2
+ extend Hashie::Extensions::DeepMerge
3
+
4
+ def initialize(*)
5
+ super { |h, k| h[k] = {} }
6
+ end
7
+
8
+ def self.name
9
+ Hash.name
10
+ end
11
+
12
+ class Hashie::Array
13
+ def self.name
14
+ Array.name
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,62 @@
1
+ module Flexite
2
+ class Data::Migrators::Yaml
3
+ def initialize
4
+ @paths = Flexite.config.paths
5
+ @roots = Flexite.config.source_roots
6
+ @hierarchy = Flexite.config.hierarchy
7
+ @data = Data::Hash.new
8
+ end
9
+
10
+ def call
11
+ @paths.each_with_object(@data) do |(name, paths), data|
12
+ paths.each do |p|
13
+ next unless File.exists?(p)
14
+ load_data(data, name, p)
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def load_data(data, name, path)
22
+ with_hierarchy(path) do |configs|
23
+ with_source_roots(data[name], configs, @roots[name])
24
+ end
25
+ end
26
+
27
+ def with_source_roots(data, configs, roots)
28
+ data.deep_merge!(configs) and return if roots.blank?
29
+
30
+ roots.each do |root|
31
+ next if configs[root].blank?
32
+ data.deep_merge!(root => configs[root])
33
+ end
34
+ end
35
+
36
+ # hierarchy = [:a, :b, :c]
37
+ #
38
+ # {
39
+ # a: {
40
+ # b: {
41
+ # c: {}
42
+ # }
43
+ # }
44
+ # }
45
+ #
46
+ #
47
+
48
+ def with_hierarchy(path)
49
+ hierarchy = @hierarchy[path]
50
+ return yield(YAML.load_file(path)) if hierarchy.blank?
51
+
52
+ new_hash = {}
53
+ leveling = new_hash
54
+ hierarchy.each do |level|
55
+ leveling = leveling[level] = {}
56
+ end
57
+
58
+ leveling.merge!(YAML.load_file(path))
59
+ yield(new_hash)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,87 @@
1
+ module Flexite
2
+ class Data::New
3
+ def initialize(migrator)
4
+ @migrator = migrator
5
+ @errors = Hash.new { |h, k| h[k] = [] }
6
+ @result = {}
7
+ end
8
+
9
+ def call
10
+ @migrator.call.each do |root, configs|
11
+ begin
12
+ @result[root] = save_root(root, configs)
13
+ rescue => exc
14
+ @errors[root] << [exc.message, exc.backtrace]
15
+ end
16
+ end
17
+
18
+ @result.tap do |result|
19
+ result[:errors] = @errors
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def save_root(root, configs)
26
+ @result[root] = {}
27
+
28
+ Config.create!(name: root) do |record|
29
+ begin
30
+ save_hash_value(record, configs)
31
+ rescue => exc
32
+ @errors[record] << [exc.message, exc.backtrace]
33
+ end
34
+ end
35
+ end
36
+
37
+ def save_entry(parent, entry)
38
+ send("save_#{entry.class.name.underscore}_value", parent, entry)
39
+ rescue => exc
40
+ @errors[parent] << [exc.message, exc.backtrace]
41
+ end
42
+
43
+ def save_hash_value(parent, hash)
44
+ parent.selectable = false
45
+
46
+ hash.each do |name, value|
47
+ entry = Config.new(name: name)
48
+ save_entry(entry, value)
49
+ parent.configs << entry
50
+ end
51
+ end
52
+
53
+ def save_array_value(parent, array)
54
+ entry = ArrEntry.new
55
+
56
+ array.each do |value|
57
+ save_entry(entry, value)
58
+ end
59
+
60
+ parent.entry = entry
61
+ end
62
+
63
+ def save_symbol_value(parent, symbol)
64
+ parent.entry = SymEntry.new(value: symbol)
65
+ end
66
+
67
+ def save_string_value(parent, string)
68
+ parent.entry = StrEntry.new(value: string)
69
+ end
70
+
71
+ def save_true_class_value(parent, _)
72
+ parent.entry = BoolEntry.new(value: 1)
73
+ end
74
+
75
+ def save_false_class_value(parent, _)
76
+ parent.entry = BoolEntry.new(value: 0)
77
+ end
78
+
79
+ def save_fixnum_value(parent, fixnum)
80
+ parent.entry = IntEntry.new(value: fixnum)
81
+ end
82
+
83
+ def save_nil_class_value(parent, nil_val)
84
+ parent.entry = Entry.new(value: nil_val)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,69 @@
1
+ require_dependency 'flexite/action_service'
2
+
3
+ module Flexite
4
+ class Entry
5
+ class ArrayCreateService < ActionService
6
+ def call
7
+ if @form.invalid?
8
+ return failure
9
+ end
10
+
11
+ process_entry
12
+ end
13
+
14
+ private
15
+
16
+ def process_entry
17
+ @record = ArrEntry.create do |record|
18
+ record.parent_id = @form.parent_id
19
+ record.parent_type = @form.parent_type
20
+ end
21
+
22
+ Entry.transaction do
23
+ create_entries(@form.new_entries, @record.id)
24
+ end
25
+
26
+ success
27
+ rescue => exc
28
+ exc_failure(exc)
29
+ end
30
+
31
+ def create_entries(new_entries, parent_id)
32
+ return if new_entries.blank?
33
+
34
+ new_entries.each do |_, entry|
35
+ if respond_to?("save_#{entry[:type].demodulize.underscore}", true)
36
+ send("save_#{entry[:type].demodulize.underscore}", entry, parent_id)
37
+ else
38
+ save_entry(entry, parent_id)
39
+ end
40
+ end
41
+ end
42
+
43
+ def save_arr_entry(entry, parent_id)
44
+ klass = entry[:type].constantize
45
+ record = klass.create({ parent_id: parent_id, parent_type: klass.base_class.sti_name }, without_protection: true)
46
+ create_entries(entry[:new_entries], record.id)
47
+ end
48
+
49
+ def save_entry(entry, parent_id)
50
+ klass = entry[:type].constantize
51
+ klass.create({ parent_id: parent_id, parent_type: klass.base_class.sti_name, value: entry[:value] }, without_protection: true)
52
+ end
53
+
54
+ protected
55
+
56
+ def failure
57
+ Result.new(success: false, endpoint: { status: 400 })
58
+ end
59
+
60
+ def exc_failure(exc)
61
+ Result.new(success: false, message: exc.message, endpoint: { status: 500 })
62
+ end
63
+
64
+ def success
65
+ Result.new(flash: { type: :success, message: 'Entry was created!' }, data: { record: @record })
66
+ end
67
+ end
68
+ end
69
+ end