haveapi-fs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/CHANGELOG +2 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +338 -0
- data/Rakefile +1 -0
- data/assets/css/bootstrap.min.css +6 -0
- data/assets/css/local.css +11 -0
- data/bin/haveapi-fs +5 -0
- data/haveapi-fs.gemspec +30 -0
- data/lib/core_ext/string.rb +9 -0
- data/lib/haveapi/fs/auth/base.rb +56 -0
- data/lib/haveapi/fs/auth/basic.rb +29 -0
- data/lib/haveapi/fs/auth/noauth.rb +9 -0
- data/lib/haveapi/fs/auth/token.rb +39 -0
- data/lib/haveapi/fs/cache.rb +71 -0
- data/lib/haveapi/fs/cleaner.rb +56 -0
- data/lib/haveapi/fs/component.rb +237 -0
- data/lib/haveapi/fs/components/action_dir.rb +106 -0
- data/lib/haveapi/fs/components/action_errors.rb +49 -0
- data/lib/haveapi/fs/components/action_exec.rb +12 -0
- data/lib/haveapi/fs/components/action_exec_edit.rb +90 -0
- data/lib/haveapi/fs/components/action_input.rb +40 -0
- data/lib/haveapi/fs/components/action_message.rb +19 -0
- data/lib/haveapi/fs/components/action_output.rb +79 -0
- data/lib/haveapi/fs/components/action_status.rb +32 -0
- data/lib/haveapi/fs/components/cache_stats.rb +19 -0
- data/lib/haveapi/fs/components/component_list.rb +24 -0
- data/lib/haveapi/fs/components/create_action_dir.rb +15 -0
- data/lib/haveapi/fs/components/delete_action_dir.rb +22 -0
- data/lib/haveapi/fs/components/directory.rb +45 -0
- data/lib/haveapi/fs/components/directory_reset.rb +8 -0
- data/lib/haveapi/fs/components/executable.rb +75 -0
- data/lib/haveapi/fs/components/file.rb +43 -0
- data/lib/haveapi/fs/components/groff_help_file.rb +9 -0
- data/lib/haveapi/fs/components/help_file.rb +28 -0
- data/lib/haveapi/fs/components/html_help_file.rb +24 -0
- data/lib/haveapi/fs/components/index_filter.rb +63 -0
- data/lib/haveapi/fs/components/info_files.rb +19 -0
- data/lib/haveapi/fs/components/instance_create.rb +20 -0
- data/lib/haveapi/fs/components/instance_edit.rb +49 -0
- data/lib/haveapi/fs/components/list_item.rb +28 -0
- data/lib/haveapi/fs/components/md_help_file.rb +24 -0
- data/lib/haveapi/fs/components/meta_dir.rb +42 -0
- data/lib/haveapi/fs/components/meta_file.rb +21 -0
- data/lib/haveapi/fs/components/parameter.rb +132 -0
- data/lib/haveapi/fs/components/pry.rb +9 -0
- data/lib/haveapi/fs/components/remote_control_file.rb +92 -0
- data/lib/haveapi/fs/components/resource_action_dir.rb +72 -0
- data/lib/haveapi/fs/components/resource_dir.rb +161 -0
- data/lib/haveapi/fs/components/resource_id.rb +15 -0
- data/lib/haveapi/fs/components/resource_instance_dir.rb +146 -0
- data/lib/haveapi/fs/components/rfuse_check.rb +3 -0
- data/lib/haveapi/fs/components/root.rb +75 -0
- data/lib/haveapi/fs/components/save_instance.rb +11 -0
- data/lib/haveapi/fs/components/unsaved_list.rb +24 -0
- data/lib/haveapi/fs/components/update_action_dir.rb +31 -0
- data/lib/haveapi/fs/context.rb +43 -0
- data/lib/haveapi/fs/exceptions.rb +0 -0
- data/lib/haveapi/fs/factory.rb +59 -0
- data/lib/haveapi/fs/fs.rb +198 -0
- data/lib/haveapi/fs/help.rb +91 -0
- data/lib/haveapi/fs/main.rb +134 -0
- data/lib/haveapi/fs/remote_control.rb +29 -0
- data/lib/haveapi/fs/version.rb +5 -0
- data/lib/haveapi/fs/worker.rb +77 -0
- data/lib/haveapi/fs.rb +65 -0
- data/templates/help/html/action_dir.erb +33 -0
- data/templates/help/html/action_errors.erb +4 -0
- data/templates/help/html/action_input.erb +40 -0
- data/templates/help/html/action_output.erb +21 -0
- data/templates/help/html/index_filter.erb +16 -0
- data/templates/help/html/layout.erb +45 -0
- data/templates/help/html/resource_action_dir.erb +18 -0
- data/templates/help/html/resource_dir.erb +18 -0
- data/templates/help/html/resource_instance_dir.erb +64 -0
- data/templates/help/html/root.erb +42 -0
- data/templates/help/md/action_dir.erb +29 -0
- data/templates/help/md/action_errors.erb +2 -0
- data/templates/help/md/action_input.erb +23 -0
- data/templates/help/md/action_output.erb +11 -0
- data/templates/help/md/index_filter.erb +11 -0
- data/templates/help/md/layout.erb +14 -0
- data/templates/help/md/resource_action_dir.erb +10 -0
- data/templates/help/md/resource_dir.erb +15 -0
- data/templates/help/md/resource_instance_dir.erb +42 -0
- data/templates/help/md/root.erb +34 -0
- metadata +231 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class DeleteActionDir < ActionDir
|
3
|
+
help_file :action_dir
|
4
|
+
|
5
|
+
def exec
|
6
|
+
ret = super
|
7
|
+
|
8
|
+
if ret.is_a?(HaveAPI::Client::Response) && ret.ok?
|
9
|
+
if @resource.is_a?(HaveAPI::Client::ResourceInstance)
|
10
|
+
id = @resource.id
|
11
|
+
|
12
|
+
else
|
13
|
+
id = @resource.prepared_args.last
|
14
|
+
end
|
15
|
+
|
16
|
+
context[:resource_dir].delete(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
ret
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
# Base class for all components that act as directories.
|
3
|
+
#
|
4
|
+
# Every directory contains some special hidden files:
|
5
|
+
#
|
6
|
+
# - `.components` contains a list of all descendant component objects that are
|
7
|
+
# created in memory
|
8
|
+
# - `.pry` is an executable that opens a developer console
|
9
|
+
class Directory < HaveAPI::Fs::Component
|
10
|
+
include HaveAPI::Fs::Help
|
11
|
+
|
12
|
+
def directory?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def contents
|
17
|
+
help_contents + %w(.reset .unsaved)
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
def new_child(name)
|
22
|
+
return help_file(name) if help_file?(name)
|
23
|
+
|
24
|
+
case name
|
25
|
+
when HaveAPI::Fs::Fs::CHECK_FILE
|
26
|
+
RFuseCheck
|
27
|
+
|
28
|
+
when :'.reset'
|
29
|
+
DirectoryReset
|
30
|
+
|
31
|
+
when :'.unsaved'
|
32
|
+
UnsavedList
|
33
|
+
|
34
|
+
when :'.components'
|
35
|
+
ComponentList
|
36
|
+
|
37
|
+
when :'.pry'
|
38
|
+
HaveAPI::Fs::Components::Pry
|
39
|
+
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
# Base class for all executables. Executables can be executed either by
|
3
|
+
# writing `1` into them or by running them, as they contain a Ruby script.
|
4
|
+
#
|
5
|
+
# The Ruby script communicates with the file system using {RemoteControlFile}.
|
6
|
+
# In short, it tells the file system to execute a component at a certain path,
|
7
|
+
# which results in the same action as when `1` is written to the file.
|
8
|
+
#
|
9
|
+
# In both cases, the file system itself does the operation, the outer process
|
10
|
+
# only signals it to do so and then waits for a reply.
|
11
|
+
#
|
12
|
+
# When the component is to be executed, method {#exec} is called.
|
13
|
+
class Executable < File
|
14
|
+
def executable?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def writable?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def read
|
23
|
+
abs_path = ::File.join(context.mountpoint, path)
|
24
|
+
|
25
|
+
<<END
|
26
|
+
#!#{RbConfig.ruby}
|
27
|
+
#
|
28
|
+
# This action can be executed either by running this file or by writing "1" to
|
29
|
+
# it, e.g.:
|
30
|
+
#
|
31
|
+
# .#{abs_path}
|
32
|
+
#
|
33
|
+
# or
|
34
|
+
#
|
35
|
+
# echo 1 > #{abs_path}
|
36
|
+
#
|
37
|
+
require 'yaml'
|
38
|
+
|
39
|
+
f = ::File.open(
|
40
|
+
'#{::File.join(context.mountpoint, '.remote_control')}',
|
41
|
+
'w+'
|
42
|
+
)
|
43
|
+
f.write(YAML.dump({
|
44
|
+
action: :execute,
|
45
|
+
path: '/#{path}',
|
46
|
+
}))
|
47
|
+
f.write(#{RemoteControlFile::MSG_DELIMITER.dump})
|
48
|
+
f.flush
|
49
|
+
f.seek(0)
|
50
|
+
|
51
|
+
ret = YAML.load(f.read)
|
52
|
+
f.close
|
53
|
+
|
54
|
+
unless ret[:status]
|
55
|
+
warn "Action failed: \#{ret[:message]}"
|
56
|
+
if ret[:errors]
|
57
|
+
ret[:errors].each do |k, v|
|
58
|
+
warn " \#{k}: \#{v.join('; ')}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
exit(ret[:status])
|
64
|
+
END
|
65
|
+
end
|
66
|
+
|
67
|
+
def write(str)
|
68
|
+
exec if str.strip == '1'
|
69
|
+
end
|
70
|
+
|
71
|
+
def exec
|
72
|
+
raise NotImplementedError
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class File < HaveAPI::Fs::Component
|
3
|
+
def file?
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
def size
|
8
|
+
read.length
|
9
|
+
end
|
10
|
+
|
11
|
+
def read
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def write(str)
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
def raw_open(path, mode, rfusefs = nil)
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def raw_read(path, offset, size, raw = nil)
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw_write(path, offset, size, buf, raw = nil)
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def raw_sync(path, datasync, raw = nil)
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def raw_truncate(path, offset, raw= nil)
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def raw_close(path, raw = nil)
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module HaveAPI::Fs::Components
|
4
|
+
class HelpFile < File
|
5
|
+
def initialize(component, format)
|
6
|
+
super()
|
7
|
+
@component = @c = component
|
8
|
+
@context = component.context
|
9
|
+
@format = format
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
def template_path(klass)
|
14
|
+
if klass.is_a?(::String)
|
15
|
+
name = klass
|
16
|
+
|
17
|
+
else
|
18
|
+
name = klass.help_file ? klass.help_file.to_s : klass.name.split('::').last.underscore
|
19
|
+
end
|
20
|
+
|
21
|
+
HaveAPI::Fs::Help.find!(::File.join(@format.to_s, name + ".erb"))
|
22
|
+
end
|
23
|
+
|
24
|
+
def layout(layout_erb)
|
25
|
+
layout_erb.result(binding { yield })
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class HtmlHelpFile < HelpFile
|
3
|
+
def initialize(*args)
|
4
|
+
super
|
5
|
+
|
6
|
+
@layout = ERB.new(::File.open(template_path('layout')).read, 0, '-')
|
7
|
+
@template = ERB.new(
|
8
|
+
::File.open(template_path(@c.class)).read,
|
9
|
+
0, '-'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def read
|
14
|
+
layout(@layout) do
|
15
|
+
@template.result(binding)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def asset(path)
|
21
|
+
::File.join(@context.mountpoint, '.assets', path)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class IndexFilter < Directory
|
3
|
+
component :index_filter
|
4
|
+
attr_reader :resource_dir, :param, :filters
|
5
|
+
|
6
|
+
def initialize(resource_dir, param, filters = {})
|
7
|
+
super()
|
8
|
+
|
9
|
+
@resource_dir = resource_dir
|
10
|
+
@param = param
|
11
|
+
@filters = filters
|
12
|
+
end
|
13
|
+
|
14
|
+
def title
|
15
|
+
"Filter by #{@param}"
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
def new_child(value)
|
20
|
+
if child = super
|
21
|
+
child
|
22
|
+
|
23
|
+
else
|
24
|
+
f = @filters.clone
|
25
|
+
f[ @param ] = value.to_s
|
26
|
+
[IndexFilterValue, @resource_dir.resource, f]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class IndexFilterValue < ResourceDir
|
32
|
+
component :resource_dir
|
33
|
+
help_file :resource_dir
|
34
|
+
|
35
|
+
def initialize(resource, filters)
|
36
|
+
super(resource)
|
37
|
+
|
38
|
+
@filters = filters
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
super
|
43
|
+
|
44
|
+
@filters.each do |k, v|
|
45
|
+
@index.find(:input).find(k).write(v)
|
46
|
+
@last = v
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def title
|
51
|
+
@last.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
def new_child(name)
|
56
|
+
child = super(name)
|
57
|
+
return child unless child
|
58
|
+
|
59
|
+
child << @filters.clone if [child].flatten.first == IndexFilter
|
60
|
+
child
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class ClientVersion < File
|
3
|
+
def read
|
4
|
+
HaveAPI::Client::VERSION + "\n"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class FsVersion < File
|
9
|
+
def read
|
10
|
+
HaveAPI::Fs::VERSION + "\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ProtocolVersion < File
|
15
|
+
def read
|
16
|
+
HaveAPI::Client::PROTOCOL_VERSION + "\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module HaveAPI::Fs::Components
|
4
|
+
class InstanceCreate < ActionExecEdit
|
5
|
+
def header
|
6
|
+
<<END
|
7
|
+
# This file is in YAML format. Lines beginning with a hash (#) are comments and
|
8
|
+
# are ignored. The new resource instance will be created once this file is saved
|
9
|
+
# and closed. The success of this operation can be later checked in
|
10
|
+
# actions/create/status.
|
11
|
+
#
|
12
|
+
# Only required parameters that need to be set are uncommented by default.
|
13
|
+
# Parameters that are not specified when this file is closed will not be sent
|
14
|
+
# to the API.
|
15
|
+
#
|
16
|
+
# To cancel the operation, either do not save the file or save it empty.
|
17
|
+
END
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module HaveAPI::Fs::Components
|
4
|
+
class InstanceEdit < ActionExecEdit
|
5
|
+
def header
|
6
|
+
<<END
|
7
|
+
# This file is in YAML format. Lines beginning with a hash (#) are comments and
|
8
|
+
# are ignored. The resource instance will be updated once this file is saved
|
9
|
+
# and closed. The success of this operation can be later checked in
|
10
|
+
# actions/update/status.
|
11
|
+
#
|
12
|
+
# To avoid updating a parameter, simply comment or delete it from this file.
|
13
|
+
# Values of parameters that are not present when the file is closed are not
|
14
|
+
# changed.
|
15
|
+
#
|
16
|
+
# To cancel the update, either do not save the file or save it empty.
|
17
|
+
END
|
18
|
+
end
|
19
|
+
|
20
|
+
def read
|
21
|
+
ret = header + "\n"
|
22
|
+
instance_dir = context[:resource_instance_dir]
|
23
|
+
|
24
|
+
@action_dir.action.input_params.each do |name, p|
|
25
|
+
if p[:type] == 'Resource'
|
26
|
+
v = instance_dir.resource.attributes[name][ p[:value_id].to_sym ]
|
27
|
+
|
28
|
+
else
|
29
|
+
v = instance_dir.resource.attributes[name]
|
30
|
+
end
|
31
|
+
|
32
|
+
ret += "# #{p[:label]}; #{p[:type]}\n"
|
33
|
+
ret += "# #{p[:description]}\n"
|
34
|
+
ret += "# Defaults to '#{p[:default]}'\n" unless p[:default].nil?
|
35
|
+
ret += "##{name}: #{v}\n\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
ret
|
39
|
+
end
|
40
|
+
|
41
|
+
def save?(data)
|
42
|
+
data.any?
|
43
|
+
end
|
44
|
+
|
45
|
+
def save
|
46
|
+
context[:resource_instance_dir].save
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class ListItem < Directory
|
3
|
+
component :list_item
|
4
|
+
|
5
|
+
def initialize(action, dir, data)
|
6
|
+
super()
|
7
|
+
|
8
|
+
@action = action
|
9
|
+
@dir = dir
|
10
|
+
@data = data
|
11
|
+
end
|
12
|
+
|
13
|
+
def contents
|
14
|
+
@action.params.keys.map(&:to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
def new_child(name)
|
19
|
+
[
|
20
|
+
Parameter,
|
21
|
+
@action,
|
22
|
+
name,
|
23
|
+
@dir,
|
24
|
+
@data,
|
25
|
+
]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class MdHelpFile < HelpFile
|
3
|
+
def initialize(*args)
|
4
|
+
super
|
5
|
+
|
6
|
+
@layout = ERB.new(::File.open(template_path('layout')).read, 0, '-')
|
7
|
+
@template = ERB.new(
|
8
|
+
::File.open(template_path(@c.class)).read,
|
9
|
+
0, '-'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def read
|
14
|
+
layout(@layout) do
|
15
|
+
@template.result(binding)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def safe_print(str)
|
21
|
+
str.to_s.gsub('_', '\_')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class MetaDir < Directory
|
3
|
+
def initialize(path)
|
4
|
+
super()
|
5
|
+
@path = path
|
6
|
+
end
|
7
|
+
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
|
11
|
+
@dir = ::Dir.new(@path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def contents
|
15
|
+
@dir.entries[2..-1]
|
16
|
+
end
|
17
|
+
|
18
|
+
def times
|
19
|
+
st = ::File.stat(@path)
|
20
|
+
[st.atime, st.mtime, st.ctime]
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def new_child(name)
|
25
|
+
if child = super
|
26
|
+
return child
|
27
|
+
end
|
28
|
+
|
29
|
+
real_name = name.to_s
|
30
|
+
return unless contents.include?(real_name)
|
31
|
+
|
32
|
+
path = ::File.join(@dir.path, real_name)
|
33
|
+
|
34
|
+
if ::File.directory?(path)
|
35
|
+
[MetaDir, path]
|
36
|
+
|
37
|
+
else
|
38
|
+
[MetaFile, path]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HaveAPI::Fs::Components
|
2
|
+
class MetaFile < File
|
3
|
+
def initialize(path)
|
4
|
+
super()
|
5
|
+
@path = path
|
6
|
+
end
|
7
|
+
|
8
|
+
def times
|
9
|
+
st = ::File.stat(@path)
|
10
|
+
[st.atime, st.mtime, st.ctime]
|
11
|
+
end
|
12
|
+
|
13
|
+
def size
|
14
|
+
::File.size(@path)
|
15
|
+
end
|
16
|
+
|
17
|
+
def read
|
18
|
+
::File.read(@path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module HaveAPI::Fs::Components
|
4
|
+
class Parameter < File
|
5
|
+
attr_reader :new_value
|
6
|
+
|
7
|
+
def initialize(action, name, dir, value = nil, opts = {})
|
8
|
+
super()
|
9
|
+
|
10
|
+
@action = action
|
11
|
+
@name = name
|
12
|
+
@dir = dir
|
13
|
+
@value = value
|
14
|
+
@set = false
|
15
|
+
@mirror = opts[:mirror]
|
16
|
+
|
17
|
+
if dir == :input
|
18
|
+
@params = @action.input_params
|
19
|
+
|
20
|
+
else
|
21
|
+
@params = @action.params
|
22
|
+
end
|
23
|
+
|
24
|
+
@desc = @params[@name]
|
25
|
+
|
26
|
+
if opts[:editable].nil?
|
27
|
+
@writable = dir == :input
|
28
|
+
|
29
|
+
else
|
30
|
+
@writable = opts[:editable]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def writable?
|
35
|
+
@writable
|
36
|
+
end
|
37
|
+
|
38
|
+
def read
|
39
|
+
str = value.to_s
|
40
|
+
str.empty? ? str : str + "\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
def write(raw)
|
44
|
+
@set = true
|
45
|
+
str = raw.strip
|
46
|
+
|
47
|
+
if str.empty?
|
48
|
+
@new_value = nil
|
49
|
+
@mirror.write_safe(@new_value) if @mirror
|
50
|
+
return
|
51
|
+
end
|
52
|
+
|
53
|
+
@new_value = case @desc[:type]
|
54
|
+
when 'Resource'
|
55
|
+
str.to_i
|
56
|
+
|
57
|
+
when 'Boolean'
|
58
|
+
HaveAPI::Client::Parameters::Typed.Boolean.to_b(str)
|
59
|
+
|
60
|
+
when 'Integer'
|
61
|
+
str.to_i
|
62
|
+
|
63
|
+
when 'Float'
|
64
|
+
str.to_f
|
65
|
+
|
66
|
+
when 'Datetime'
|
67
|
+
Time.iso8601(str)
|
68
|
+
|
69
|
+
else
|
70
|
+
str.strip
|
71
|
+
end
|
72
|
+
|
73
|
+
changed
|
74
|
+
@mirror.write_safe(@new_value) if @mirror
|
75
|
+
|
76
|
+
rescue => e
|
77
|
+
@set = false
|
78
|
+
raise e
|
79
|
+
end
|
80
|
+
|
81
|
+
def write_safe(v)
|
82
|
+
@new_value = v
|
83
|
+
@set = true
|
84
|
+
changed
|
85
|
+
end
|
86
|
+
|
87
|
+
def value
|
88
|
+
# Value in ResourceInstance
|
89
|
+
# Value in hash
|
90
|
+
# Value changed, saved in instance variable
|
91
|
+
|
92
|
+
hash = @value.is_a?(::Hash)
|
93
|
+
|
94
|
+
if @desc[:type] == 'Resource'
|
95
|
+
return @new_value if @new_value
|
96
|
+
return nil if @value.nil?
|
97
|
+
return nil if @value.attributes[@name].nil?
|
98
|
+
@value.attributes[@name][@desc[:value_id].to_sym]
|
99
|
+
|
100
|
+
else
|
101
|
+
if @new_value
|
102
|
+
v = @new_value
|
103
|
+
|
104
|
+
else
|
105
|
+
return nil if @value.nil?
|
106
|
+
|
107
|
+
v = hash ? @value[@name] : @value.send(@name)
|
108
|
+
end
|
109
|
+
|
110
|
+
case @desc[:type]
|
111
|
+
when 'Boolean'
|
112
|
+
v ? 1 : 0
|
113
|
+
|
114
|
+
when 'Datetime'
|
115
|
+
v.is_a?(::Time) ? v.iso8601 : v
|
116
|
+
|
117
|
+
else
|
118
|
+
v
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def set?
|
125
|
+
@set
|
126
|
+
end
|
127
|
+
|
128
|
+
def unsaved?(n = nil)
|
129
|
+
set?
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|